diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h
index 97872762839323dde9abfa5400f3bd82596a8db8..63441dc728d0a88ead50a01d9679611e5d2f01e7 100644
--- a/servers/slapd/back-meta/back-meta.h
+++ b/servers/slapd/back-meta/back-meta.h
@@ -69,12 +69,14 @@ struct ldaprwmap {
 	 * will be disabled */
 	BerVarray rwm_suffix_massage;
 #endif /* !ENABLE_REWRITE */
+	BerVarray rwm_bva_rewrite;
 
 	/*
 	 * Attribute/objectClass mapping
 	 */
 	struct ldapmap rwm_oc;
 	struct ldapmap rwm_at;
+	BerVarray rwm_bva_map;
 };
 
 /* Whatever context ldap_back_dn_massage needs... */
@@ -265,8 +267,8 @@ typedef struct metasubtree_t {
 	union {
 		struct berval msu_dn;
 		struct {
+			struct berval msr_regex_pattern;
 			regex_t msr_regex;
-			char *msr_regex_pattern;
 		} msu_regex;
 	} ms_un;
 #define ms_dn ms_un.msu_dn
@@ -287,6 +289,11 @@ typedef struct metacommon_t {
 	unsigned		mc_flags;
 #define	META_BACK_CMN_ISSET(mc,f)		( ( (mc)->mc_flags & (f) ) == (f) )
 #define	META_BACK_CMN_QUARANTINE(mc)		META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_QUARANTINE )
+#define	META_BACK_CMN_CHASE_REFERRALS(mc)	META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_CHASE_REFERRALS )
+#define	META_BACK_CMN_NOREFS(mc)		META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_NOREFS )
+#define	META_BACK_CMN_NOUNDEFFILTER(mc)		META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_NOUNDEFFILTER )
+#define	META_BACK_CMN_SAVECRED(mc)		META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_SAVECRED )
+#define	META_BACK_CMN_ST_REQUEST(mc)		META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_ST_REQUEST )
 
 #ifdef SLAPD_META_CLIENT_PR
 	/*
@@ -668,6 +675,9 @@ meta_dncache_delete_entry(
 extern void
 meta_dncache_free( void *entry );
 
+extern void
+meta_back_map_free( struct ldapmap *lm );
+
 extern int
 meta_subtree_destroy( metasubtree_t *ms );
 
diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c
index 6fd4e08db54aee2705ec7d5851a84d9851f32838..54b4c8795a66c447620583d72436d8d2b6a308e8 100644
--- a/servers/slapd/back-meta/config.c
+++ b/servers/slapd/back-meta/config.c
@@ -291,14 +291,16 @@ static ConfigTable metacfg[] = {
 			"SINGLE-VALUE )",
 		NULL, NULL },
 
-	{ "rewrite", "arglist", 2, 4, STRLENOF( "rewrite" ),
-		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
+	{ "rewrite", "arglist", 2, 0, STRLENOF( "rewrite" ),
+		ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
 		meta_back_cf_gen, "( OLcfgDbAt:3.101 "
 			"NAME 'olcDbRewrite' "
 			"DESC 'DN rewriting rules' "
-			"SYNTAX OMsDirectoryString )",
+			"EQUALITY caseIgnoreMatch "
+			"SYNTAX OMsDirectoryString "
+			"X-ORDERED 'VALUES' )",
 		NULL, NULL },
-	{ "suffixmassage", "virtual> <real", 3, 3, 0,
+	{ "suffixmassage", "virtual> <real", 2, 3, 0,
 		ARG_MAGIC|LDAP_BACK_CFG_SUFFIXM,
 		meta_back_cf_gen, NULL, NULL, NULL },
 
@@ -307,7 +309,9 @@ static ConfigTable metacfg[] = {
 		meta_back_cf_gen, "( OLcfgDbAt:3.102 "
 			"NAME 'olcDbMap' "
 			"DESC 'Map attribute and objectclass names' "
-			"SYNTAX OMsDirectoryString )",
+			"EQUALITY caseIgnoreMatch "
+			"SYNTAX OMsDirectoryString "
+			"X-ORDERED 'VALUES' )",
 		NULL, NULL },
 
 	{ "subtree-exclude", "pattern", 2, 2, 0,
@@ -315,6 +319,7 @@ static ConfigTable metacfg[] = {
 		meta_back_cf_gen, "( OLcfgDbAt:3.103 "
 			"NAME 'olcDbSubtreeExclude' "
 			"DESC 'DN of subtree to exclude from target' "
+			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString )",
 		NULL, NULL },
 	{ "subtree-include", "pattern", 2, 2, 0,
@@ -322,6 +327,7 @@ static ConfigTable metacfg[] = {
 		meta_back_cf_gen, "( OLcfgDbAt:3.104 "
 			"NAME 'olcDbSubtreeInclude' "
 			"DESC 'DN of subtree to include in target' "
+			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString )",
 		NULL, NULL },
 	{ "default-target", "[none|<target ID>]", 1, 2, 0,
@@ -341,7 +347,7 @@ static ConfigTable metacfg[] = {
 			"SINGLE-VALUE )",
 		NULL, NULL },
 	{ "bind-timeout", "microseconds", 2, 2, 0,
-		ARG_MAGIC|LDAP_BACK_CFG_BIND_TIMEOUT,
+		ARG_MAGIC|ARG_ULONG|LDAP_BACK_CFG_BIND_TIMEOUT,
 		meta_back_cf_gen, "( OLcfgDbAt:3.107 "
 			"NAME 'olcDbBindTimeout' "
 			"DESC 'bind timeout' "
@@ -374,7 +380,7 @@ static ConfigTable metacfg[] = {
 		ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_PSEUDOROOTDN,
 		meta_back_cf_gen, NULL, NULL, NULL },
 	{ "nretries", "NEVER|forever|<number>", 2, 2, 0,
-		ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_NRETRIES,
+		ARG_MAGIC|LDAP_BACK_CFG_NRETRIES,
 		meta_back_cf_gen, "( OLcfgDbAt:3.110 "
 			"NAME 'olcDbNretries' "
 			"DESC 'retry handling' "
@@ -382,7 +388,7 @@ static ConfigTable metacfg[] = {
 			"SINGLE-VALUE )",
 		NULL, NULL },
 	{ "client-pr", "accept-unsolicited|disable|<size>", 2, 2, 0,
-		ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_CLIENT_PR,
+		ARG_MAGIC|LDAP_BACK_CFG_CLIENT_PR,
 		meta_back_cf_gen, "( OLcfgDbAt:3.111 "
 			"NAME 'olcDbClientPr' "
 			"DESC 'PagedResults handling' "
@@ -393,6 +399,7 @@ static ConfigTable metacfg[] = {
 	{ "", "", 0, 0, 0, ARG_IGNORED,
 		NULL, "( OLcfgDbAt:3.100 NAME 'olcMetaSub' "
 			"DESC 'Placeholder to name a Target entry' "
+			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString "
 			"SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
 
@@ -485,6 +492,7 @@ meta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
 		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
 			"olcMetaSub=" SLAP_X_ORDERED_FMT "uri", i );
 		c->ca_private = mi->mi_targets[i];
+		c->valx = i;
 		config_build_entry( op, rs, p->e_private, c,
 			&bv, &metaocs[1], NULL );
 	}
@@ -493,22 +501,14 @@ meta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
 }
 
 static int
-meta_back_new_target(
-	metatarget_t	**mtp )
+meta_rwi_init( struct rewrite_info **rwm_rw )
 {
 	char			*rargv[ 3 ];
-	metatarget_t		*mt;
-
-	*mtp = NULL;
 
-	mt = ch_calloc( sizeof( metatarget_t ), 1 );
-
-	mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
-	if ( mt->mt_rwmap.rwm_rw == NULL ) {
-		ch_free( mt );
+	*rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+	if ( *rwm_rw == NULL ) {
 		return -1;
 	}
-
 	/*
 	 * the filter rewrite as a string must be disabled
 	 * by default; it can be re-enabled by adding rules;
@@ -517,12 +517,30 @@ meta_back_new_target(
 	rargv[ 0 ] = "rewriteContext";
 	rargv[ 1 ] = "searchFilter";
 	rargv[ 2 ] = NULL;
-	rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
+	rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
 
 	rargv[ 0 ] = "rewriteContext";
 	rargv[ 1 ] = "default";
 	rargv[ 2 ] = NULL;
-	rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
+	rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
+
+	return 0;
+}
+
+static int
+meta_back_new_target(
+	metatarget_t	**mtp )
+{
+	metatarget_t		*mt;
+
+	*mtp = NULL;
+
+	mt = ch_calloc( sizeof( metatarget_t ), 1 );
+
+	if ( meta_rwi_init( &mt->mt_rwmap.rwm_rw )) {
+		ch_free( mt );
+		return -1;
+	}
 
 	ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
 
@@ -538,6 +556,129 @@ meta_back_new_target(
 	return 0;
 }
 
+/* Validation for suffixmassage_config */
+static int
+meta_suffixm_config(
+	ConfigArgs *c,
+	metatarget_t *mt
+)
+{
+	BackendDB 	*tmp_bd;
+	struct berval	dn, nvnc, pvnc, nrnc, prnc;
+	int j, rc;
+
+	/*
+	 * syntax:
+	 *
+	 * 	suffixmassage <suffix> <massaged suffix>
+	 *
+	 * the <suffix> field must be defined as a valid suffix
+	 * (or suffixAlias?) for the current database;
+	 * the <massaged suffix> shouldn't have already been
+	 * defined as a valid suffix or suffixAlias for the
+	 * current server
+	 */
+
+	ber_str2bv( c->argv[ 1 ], 0, 0, &dn );
+	if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
+		snprintf( c->cr_msg, sizeof( c->cr_msg ),
+			"suffix \"%s\" is invalid",
+			c->argv[1] );
+		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+		return 1;
+	}
+
+	for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
+		if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) {
+			break;
+		}
+	}
+
+	if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
+		snprintf( c->cr_msg, sizeof( c->cr_msg ),
+			"suffix \"%s\" must be within the database naming context",
+			c->argv[1] );
+		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+		free( pvnc.bv_val );
+		free( nvnc.bv_val );
+		return 1;
+	}
+
+	ber_str2bv( c->argv[ 2 ], 0, 0, &dn );
+	if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
+		snprintf( c->cr_msg, sizeof( c->cr_msg ),
+			"massaged suffix \"%s\" is invalid",
+			c->argv[2] );
+		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+		free( pvnc.bv_val );
+		free( nvnc.bv_val );
+		return 1;
+	}
+
+	tmp_bd = select_backend( &nrnc, 0 );
+	if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) {
+		Debug( LDAP_DEBUG_ANY,
+	"%s: warning: <massaged suffix> \"%s\" resolves to this database, in "
+	"\"suffixMassage <suffix> <massaged suffix>\"\n",
+			c->log, prnc.bv_val, 0 );
+	}
+
+	/*
+	 * The suffix massaging is emulated by means of the
+	 * rewrite capabilities
+	 */
+	rc = suffix_massage_config( mt->mt_rwmap.rwm_rw,
+			&pvnc, &nvnc, &prnc, &nrnc );
+
+	free( pvnc.bv_val );
+	free( nvnc.bv_val );
+	free( prnc.bv_val );
+	free( nrnc.bv_val );
+
+	return rc;
+}
+
+static int
+slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
+{
+	int		i;
+	BerVarray	bva = NULL;
+	char		ibuf[32], *ptr;
+	struct berval	idx;
+
+	assert( in != NULL );
+
+	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
+		/* count'em */ ;
+
+	if ( i == 0 ) {
+		return 1;
+	}
+
+	idx.bv_val = ibuf;
+
+	bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
+	BER_BVZERO( &bva[ 0 ] );
+
+	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
+		idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
+		if ( idx.bv_len >= sizeof( ibuf ) ) {
+			ber_bvarray_free( bva );
+			return 1;
+		}
+
+		bva[i].bv_len = idx.bv_len + in[i].bv_len;
+		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
+		ptr = lutil_strcopy( bva[i].bv_val, ibuf );
+		ptr = lutil_strcopy( ptr, in[i].bv_val );
+		*ptr = '\0';
+		BER_BVZERO( &bva[ i + 1 ] );
+	}
+
+	*out = bva;
+	return 0;
+}
+
 int
 meta_subtree_destroy( metasubtree_t *ms )
 {
@@ -553,7 +694,7 @@ meta_subtree_destroy( metasubtree_t *ms )
 
 	case META_ST_REGEX:
 		regfree( &ms->ms_regex );
-		ch_free( ms->ms_regex_pattern );
+		ber_memfree( ms->ms_regex_pattern.bv_val );
 		break;
 
 	default:
@@ -565,6 +706,46 @@ meta_subtree_destroy( metasubtree_t *ms )
 	return 0;
 }
 
+static struct berval st_styles[] = {
+	BER_BVC("subtree"),
+	BER_BVC("children"),
+	BER_BVC("regex")
+};
+
+static int
+meta_subtree_unparse(
+	ConfigArgs *c,
+	metatarget_t *mt )
+{
+	metasubtree_t	*ms;
+	struct berval bv, *style;
+
+	if ( !mt->mt_subtree )
+		return 1;
+
+	/* can only be one of exclude or include */
+	if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude )
+		return 1;
+
+	bv.bv_val = c->cr_msg;
+	for ( ms=mt->mt_subtree; ms; ms=ms->ms_next ) {
+		if (ms->ms_type == META_ST_SUBTREE)
+			style = &st_styles[0];
+		else if ( ms->ms_type == META_ST_SUBORDINATE )
+			style = &st_styles[1];
+		else if ( ms->ms_type == META_ST_REGEX )
+			style = &st_styles[2];
+		else {
+			assert(0);
+			continue;
+		}
+		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
+			"dn.%s:%s", style->bv_val, ms->ms_dn.bv_val );
+		value_add_one( &c->rvalue_vals, &bv );
+	}
+	return 0;
+}
+
 static int
 meta_subtree_config(
 	metatarget_t *mt,
@@ -681,7 +862,7 @@ meta_subtree_config(
 			ch_free( ms );
 			return 1;
 		}
-		ms->ms_regex_pattern = ch_strdup( pattern );
+		ber_str2bv( pattern, 0, 1, &ms->ms_regex_pattern );
 		} break;
 	}
 
@@ -741,7 +922,7 @@ meta_subtree_config(
 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
 						Debug( LDAP_DEBUG_CONFIG,
 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
-							c->log, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
+							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
 					}
 					break;
 				}
@@ -795,7 +976,7 @@ meta_subtree_config(
 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
 						Debug( LDAP_DEBUG_CONFIG,
 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
-							c->log, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
+							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
 					}
 					break;
 				}
@@ -808,7 +989,7 @@ meta_subtree_config(
 					if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
 						Debug( LDAP_DEBUG_CONFIG,
 							"%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n",
-							c->log, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern );
+							c->log, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern.bv_val );
 					}
 					break;
 
@@ -902,19 +1083,493 @@ meta_back_cf_gen( ConfigArgs *c )
 		if ( !mi )
 			return 1;
 
-		if ( c->type >= LDAP_BACK_CFG_LAST_BASE ) {
+		if ( c->table == Cft_Database ) {
+			mt = NULL;
+			mc = &mi->mi_mc;
+		} else {
 			mt = c->ca_private;
-			if ( mt )
-				mc = &mt->mt_mc;
-			else
-				mc = &mi->mi_mc;
+			mc = &mt->mt_mc;
 		}
 
 		switch( c->type ) {
-		case LDAP_BACK_CFG_URI:
-			ber_str2bv( mt->mt_uri, 0, 0, &bv );
+		/* Base attrs */
+		case LDAP_BACK_CFG_CONN_TTL:
+			if ( mi->mi_conn_ttl == 0 ) {
+				return 1;
+			} else {
+				char	buf[ SLAP_TEXT_BUFLEN ];
+
+				lutil_unparse_time( buf, sizeof( buf ), mi->mi_conn_ttl );
+				ber_str2bv( buf, 0, 0, &bv );
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		case LDAP_BACK_CFG_DNCACHE_TTL:
+			if ( mi->mi_cache.ttl == META_DNCACHE_DISABLED ) {
+				return 1;
+			} else if ( mi->mi_cache.ttl == META_DNCACHE_FOREVER ) {
+				BER_BVSTR( &bv, "forever" );
+			} else {
+				char	buf[ SLAP_TEXT_BUFLEN ];
+
+				lutil_unparse_time( buf, sizeof( buf ), mi->mi_cache.ttl );
+				ber_str2bv( buf, 0, 0, &bv );
+			}
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+
+		case LDAP_BACK_CFG_IDLE_TIMEOUT:
+			if ( mi->mi_idle_timeout == 0 ) {
+				return 1;
+			} else {
+				char	buf[ SLAP_TEXT_BUFLEN ];
+
+				lutil_unparse_time( buf, sizeof( buf ), mi->mi_idle_timeout );
+				ber_str2bv( buf, 0, 0, &bv );
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		case LDAP_BACK_CFG_ONERR:
+			enum_to_verb( onerr_mode, mi->mi_flags & META_BACK_F_ONERR_MASK, &bv );
+			if ( BER_BVISNULL( &bv )) {
+				rc = 1;
+			} else {
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
+			c->value_int = META_BACK_DEFER_ROOTDN_BIND( mi );
+			break;
+
+		case LDAP_BACK_CFG_SINGLECONN:
+			c->value_int = LDAP_BACK_SINGLECONN( mi );
+			break;
+
+		case LDAP_BACK_CFG_USETEMP:
+			c->value_int = LDAP_BACK_USE_TEMPORARIES( mi );
+			break;
+
+		case LDAP_BACK_CFG_CONNPOOLMAX:
+			c->value_int = mi->mi_conn_priv_max;
+			break;
+
+		/* common attrs */
+		case LDAP_BACK_CFG_BIND_TIMEOUT:
+			if ( mc->mc_bind_timeout.tv_sec == 0 &&
+				mc->mc_bind_timeout.tv_usec == 0 ) {
+				return 1;
+			} else {
+				c->value_ulong = mc->mc_bind_timeout.tv_sec * 1000000UL +
+					mc->mc_bind_timeout.tv_usec;
+			}
+			break;
+
+		case LDAP_BACK_CFG_CANCEL: {
+			slap_mask_t	mask = LDAP_BACK_F_CANCEL_MASK2;
+
+			if ( mt && META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
+				mask &= ~LDAP_BACK_F_CANCEL_EXOP;
+			}
+			enum_to_verb( cancel_mode, (mc->mc_flags & mask), &bv );
+			if ( BER_BVISNULL( &bv ) ) {
+				/* there's something wrong... */
+				assert( 0 );
+				rc = 1;
+
+			} else {
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			} break;
+
+		case LDAP_BACK_CFG_CHASE:
+			c->value_int = META_BACK_CMN_CHASE_REFERRALS(mc);
+			break;
+
+#ifdef SLAPD_META_CLIENT_PR
+		case LDAP_BACK_CFG_CLIENT_PR:
+			if ( mc->mc_ps == META_CLIENT_PR_DISABLE ) {
+				return 1;
+			} else if ( mc->mc_ps == META_CLIENT_PR_ACCEPT_UNSOLICITED ) {
+				BER_BVSTR( &bv, "accept-unsolicited" );
+			} else {
+				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mc->mc_ps );
+				bv.bv_val = c->cr_msg;
+			}
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+#endif /* SLAPD_META_CLIENT_PR */
+
+		case LDAP_BACK_CFG_DEFAULT_T:
+			if ( mt || mi->mi_defaulttarget == META_DEFAULT_TARGET_NONE )
+				return 1;
+			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mi->mi_defaulttarget );
+			bv.bv_val = c->cr_msg;
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+
+		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
+			if ( mc->mc_network_timeout == 0 ) {
+				return 1;
+			}
+			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%ld",
+				mc->mc_network_timeout );
+			bv.bv_val = c->cr_msg;
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+
+		case LDAP_BACK_CFG_NOREFS:
+			c->value_int = META_BACK_CMN_NOREFS(mc);
+			break;
+
+		case LDAP_BACK_CFG_NOUNDEFFILTER:
+			c->value_int = META_BACK_CMN_NOUNDEFFILTER(mc);
+			break;
+
+		case LDAP_BACK_CFG_NRETRIES:
+			if ( mc->mc_nretries == META_RETRY_FOREVER ) {
+				BER_BVSTR( &bv, "forever" );
+			} else if ( mc->mc_nretries == META_RETRY_NEVER ) {
+				BER_BVSTR( &bv, "never" );
+			} else {
+				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d",
+					mc->mc_nretries );
+				bv.bv_val = c->cr_msg;
+			}
+			value_add_one( &c->rvalue_vals, &bv );
+			break;
+
+		case LDAP_BACK_CFG_QUARANTINE:
+			if ( !META_BACK_CMN_QUARANTINE( mc )) {
+				rc = 1;
+				break;
+			}
+			rc = mi->mi_ldap_extra->retry_info_unparse( &mc->mc_quarantine, &bv );
+			if ( rc == 0 ) {
+				ber_bvarray_add( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		case LDAP_BACK_CFG_REBIND:
+			c->value_int = META_BACK_CMN_SAVECRED(mc);
+			break;
+
+		case LDAP_BACK_CFG_TIMEOUT:
+			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+				if ( mc->mc_timeout[ i ] != 0 ) {
+					break;
+				}
+			}
+
+			if ( i == SLAP_OP_LAST ) {
+				return 1;
+			}
+
+			BER_BVZERO( &bv );
+			slap_cf_aux_table_unparse( mc->mc_timeout, &bv, timeout_table );
+
+			if ( BER_BVISNULL( &bv ) ) {
+				return 1;
+			}
+
+			for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
+				/* count spaces */ ;
+
+			if ( i ) {
+				bv.bv_len -= i;
+				AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
+					bv.bv_len + 1 );
+			}
+
 			ber_bvarray_add( &c->rvalue_vals, &bv );
 			break;
+
+		case LDAP_BACK_CFG_VERSION:
+			if ( mc->mc_version == 0 )
+				return 1;
+			c->value_int = mc->mc_version;
+			break;
+
+#ifdef SLAP_CONTROL_X_SESSION_TRACKING
+		case LDAP_BACK_CFG_ST_REQUEST:
+			c->value_int = META_BACK_CMN_ST_REQUEST( mc );
+			break;
+#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
+
+		case LDAP_BACK_CFG_T_F:
+			enum_to_verb( t_f_mode, (mc->mc_flags & LDAP_BACK_F_T_F_MASK2), &bv );
+			if ( BER_BVISNULL( &bv ) ) {
+				/* there's something wrong... */
+				assert( 0 );
+				rc = 1;
+
+			} else {
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		case LDAP_BACK_CFG_TLS: {
+			struct berval bc = BER_BVNULL, bv2;
+
+			if (( mc->mc_flags & LDAP_BACK_F_TLS_MASK ) == LDAP_BACK_F_NONE ) {
+				rc = 1;
+				break;
+			}
+			enum_to_verb( tls_mode, ( mc->mc_flags & LDAP_BACK_F_TLS_MASK ), &bv );
+			assert( !BER_BVISNULL( &bv ) );
+
+			if ( mt ) {
+				bindconf_tls_unparse( &mt->mt_tls, &bc );
+			}
+
+			if ( !BER_BVISEMPTY( &bc )) {
+				bv2.bv_len = bv.bv_len + bc.bv_len + 1;
+				bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
+				strcpy( bv2.bv_val, bv.bv_val );
+				bv2.bv_val[bv.bv_len] = ' ';
+				strcpy( &bv2.bv_val[bv.bv_len + 1], bc.bv_val );
+				ber_memfree( bc.bv_val );
+				ber_bvarray_add( &c->rvalue_vals, &bv2 );
+			} else {
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			} break;
+
+		/* target attrs */
+		case LDAP_BACK_CFG_URI: {
+			char *p2, *p1 = strchr( mt->mt_uri, ' ' );
+			bv.bv_len = strlen( mt->mt_uri ) + 1 + mt->mt_psuffix.bv_len;
+			bv.bv_val = ch_malloc( bv.bv_len + 1 );
+			if ( p1 ) {
+				p2 = lutil_strncopy( bv.bv_val, mt->mt_uri, p1 - mt->mt_uri );
+			} else {
+				p2 = lutil_strcopy( bv.bv_val, mt->mt_uri );
+			}
+			*p2++ = '/';
+			p2 = lutil_strcopy( p2, mt->mt_psuffix.bv_val );
+			if ( p1 ) {
+				strcpy( p2, p1 );
+			}
+			value_add_one( &c->rvalue_vals, &bv );
+			} break;
+
+		case LDAP_BACK_CFG_ACL_AUTHCDN:
+		case LDAP_BACK_CFG_ACL_PASSWD:
+			/* FIXME no point here, there is no code implementing
+			 * their features. Was this supposed to implement
+			 * acl-bind like back-ldap?
+			 */
+			rc = 1;
+			break;
+
+		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
+			BerVarray	*bvp;
+			int		i;
+			struct berval	bv = BER_BVNULL;
+			char		buf[SLAP_TEXT_BUFLEN];
+
+			bvp = &mt->mt_idassert_authz;
+			if ( *bvp == NULL ) {
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
+				{
+					BER_BVSTR( &bv, "*" );
+					value_add_one( &c->rvalue_vals, &bv );
+
+				} else {
+					rc = 1;
+				}
+				break;
+			}
+
+			for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ ) {
+				char *ptr;
+				int len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
+				bv.bv_len = ((*bvp)[ i ]).bv_len + len;
+				bv.bv_val = ber_memrealloc( bv.bv_val, bv.bv_len + 1 );
+				ptr = bv.bv_val;
+				ptr = lutil_strcopy( ptr, buf );
+				ptr = lutil_strncopy( ptr, ((*bvp)[ i ]).bv_val, ((*bvp)[ i ]).bv_len );
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			if ( bv.bv_val ) {
+				ber_memfree( bv.bv_val );
+			}
+			break;
+		}
+
+		case LDAP_BACK_CFG_IDASSERT_BIND: {
+			int		i;
+			struct berval	bc = BER_BVNULL;
+			char		*ptr;
+
+			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) {
+				return 1;
+			} else {
+				ber_len_t	len;
+
+				switch ( mt->mt_idassert_mode ) {
+				case LDAP_BACK_IDASSERT_OTHERID:
+				case LDAP_BACK_IDASSERT_OTHERDN:
+					break;
+
+				default: {
+					struct berval	mode = BER_BVNULL;
+
+					enum_to_verb( idassert_mode, mt->mt_idassert_mode, &mode );
+					if ( BER_BVISNULL( &mode ) ) {
+						/* there's something wrong... */
+						assert( 0 );
+						rc = 1;
+
+					} else {
+						bv.bv_len = STRLENOF( "mode=" ) + mode.bv_len;
+						bv.bv_val = ch_malloc( bv.bv_len + 1 );
+
+						ptr = lutil_strcopy( bv.bv_val, "mode=" );
+						ptr = lutil_strcopy( ptr, mode.bv_val );
+					}
+					break;
+				}
+				}
+
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) {
+					len = bv.bv_len + STRLENOF( "authz=native" );
+
+					if ( !BER_BVISEMPTY( &bv ) ) {
+						len += STRLENOF( " " );
+					}
+
+					bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
+
+					ptr = &bv.bv_val[ bv.bv_len ];
+
+					if ( !BER_BVISEMPTY( &bv ) ) {
+						ptr = lutil_strcopy( ptr, " " );
+					}
+
+					(void)lutil_strcopy( ptr, "authz=native" );
+				}
+
+				len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override,obsolete-encoding-workaround,proxy-authz-non-critical,dn-authzid" );
+				/* flags */
+				if ( !BER_BVISEMPTY( &bv ) ) {
+					len += STRLENOF( " " );
+				}
+
+				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
+
+				ptr = &bv.bv_val[ bv.bv_len ];
+
+				if ( !BER_BVISEMPTY( &bv ) ) {
+					ptr = lutil_strcopy( ptr, " " );
+				}
+
+				ptr = lutil_strcopy( ptr, "flags=" );
+
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+					ptr = lutil_strcopy( ptr, "prescriptive" );
+				} else {
+					ptr = lutil_strcopy( ptr, "non-prescriptive" );
+				}
+
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
+					ptr = lutil_strcopy( ptr, ",override" );
+				}
+
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+					ptr = lutil_strcopy( ptr, ",obsolete-proxy-authz" );
+
+				} else if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+					ptr = lutil_strcopy( ptr, ",obsolete-encoding-workaround" );
+				}
+
+				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) {
+					ptr = lutil_strcopy( ptr, ",proxy-authz-critical" );
+
+				} else {
+					ptr = lutil_strcopy( ptr, ",proxy-authz-non-critical" );
+				}
+
+				switch ( mt->mt_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) {
+				case LDAP_BACK_AUTH_DN_AUTHZID:
+					ptr = lutil_strcopy( ptr, ",dn-authzid" );
+					break;
+
+				case LDAP_BACK_AUTH_DN_WHOAMI:
+					ptr = lutil_strcopy( ptr, ",dn-whoami" );
+					break;
+
+				default:
+#if 0 /* implicit */
+					ptr = lutil_strcopy( ptr, ",dn-none" );
+#endif
+					break;
+				}
+
+				bv.bv_len = ( ptr - bv.bv_val );
+				/* end-of-flags */
+			}
+
+			bindconf_unparse( &mt->mt_idassert.si_bc, &bc );
+
+			if ( !BER_BVISNULL( &bv ) ) {
+				ber_len_t	len = bv.bv_len + bc.bv_len;
+
+				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
+
+				assert( bc.bv_val[ 0 ] == ' ' );
+
+				ptr = lutil_strcopy( &bv.bv_val[ bv.bv_len ], bc.bv_val );
+				free( bc.bv_val );
+				bv.bv_len = ptr - bv.bv_val;
+
+			} else {
+				for ( i = 0; isspace( (unsigned char) bc.bv_val[ i ] ); i++ )
+					/* count spaces */ ;
+
+				if ( i ) {
+					bc.bv_len -= i;
+					AC_MEMCPY( bc.bv_val, &bc.bv_val[ i ], bc.bv_len + 1 );
+				}
+
+				bv = bc;
+			}
+
+			ber_bvarray_add( &c->rvalue_vals, &bv );
+
+			break;
+		}
+
+		case LDAP_BACK_CFG_SUFFIXM:	/* unused */
+		case LDAP_BACK_CFG_REWRITE:
+			if ( mt->mt_rwmap.rwm_bva_rewrite == NULL ) {
+				rc = 1;
+			} else {
+				rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_rewrite, &c->rvalue_vals );
+			}
+			break;
+
+		case LDAP_BACK_CFG_MAP:
+			if ( mt->mt_rwmap.rwm_bva_map == NULL ) {
+				rc = 1;
+			} else {
+				rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_map, &c->rvalue_vals );
+			}
+			break;
+
+		case LDAP_BACK_CFG_SUBTREE_EX:
+		case LDAP_BACK_CFG_SUBTREE_IN:
+			rc = meta_subtree_unparse( c, mt );
+			break;
+
+		/* replaced by idassert */
+		case LDAP_BACK_CFG_PSEUDOROOTDN:
+		case LDAP_BACK_CFG_PSEUDOROOTPW:
+			rc = 1;
+			break;
+
 		default:
 			rc = 1;
 		}
@@ -943,6 +1598,16 @@ meta_back_cf_gen( ConfigArgs *c )
 			}
 		}
 	} else {
+		if ( c->table == Cft_Database ) {
+			mt = NULL;
+			mc = &mi->mi_mc;
+		} else {
+			mt = c->ca_private;
+			if ( mt )
+				mc = &mt->mt_mc;
+			else
+				mc = NULL;
+		}
 	}
 
 	switch( c->type ) {
@@ -988,8 +1653,6 @@ meta_back_cf_gen( ConfigArgs *c )
 		mt->mt_urllist_f = mi->mi_urllist_f;
 		mt->mt_urllist_p = mt;
 
-		mt->mt_nretries = mi->mi_nretries;
-		mt->mt_quarantine = mi->mi_quarantine;
 		if ( META_BACK_QUARANTINE( mi ) ) {
 			ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
 		}
@@ -1254,21 +1917,11 @@ meta_back_cf_gen( ConfigArgs *c )
 		mi->mi_conn_ttl = (time_t)t;
 		} break;
 
-	case LDAP_BACK_CFG_BIND_TIMEOUT: {
+	case LDAP_BACK_CFG_BIND_TIMEOUT:
 	/* bind timeout when connecting to ldap servers */
-		unsigned long	t;
-
-		if ( lutil_atoul( &t, c->argv[ 1 ] ) != 0 ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"unable to parse bind timeout \"%s\"",
-				c->argv[ 1 ] );
-			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
-			return 1;
-
-		}
-		mc->mc_bind_timeout.tv_sec = t/1000000;
-		mc->mc_bind_timeout.tv_usec = t%1000000;
-		} break;
+		mc->mc_bind_timeout.tv_sec = c->value_ulong/1000000;
+		mc->mc_bind_timeout.tv_usec = c->value_ulong%1000000;
+		break;
 
 	case LDAP_BACK_CFG_ACL_AUTHCDN:
 	/* name to use for meta_back_group */
@@ -1329,17 +1982,13 @@ meta_back_cf_gen( ConfigArgs *c )
 		mc->mc_flags |= tls_mode[i].mask;
 
 		if ( c->argc > 2 ) {
-			metatarget_t	*mt = NULL;
-
-			if ( mi->mi_ntargets - 1 < 0 ) {
+			if ( c->op == SLAP_CONFIG_ADD && mi->mi_ntargets == 0 ) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
 					"need \"uri\" directive first" );
 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 				return 1;
 			}
 
-			mt = mi->mi_targets[ mi->mi_ntargets - 1 ];
-
 			for ( i = 2; i < c->argc; i++ ) {
 				if ( bindconf_tls_parse( c->argv[i], &mt->mt_tls ))
 					return 1;
@@ -1639,92 +2288,224 @@ idassert-authzFrom	"dn:<rootdn>"
 		break;
 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
 
-	case LDAP_BACK_CFG_SUFFIXM: {
-	/* dn massaging */
-		BackendDB 	*tmp_bd;
-		struct berval	dn, nvnc, pvnc, nrnc, prnc;
-		int j;
-
-		/*
-		 * syntax:
-		 *
-		 * 	suffixmassage <suffix> <massaged suffix>
-		 *
-		 * the <suffix> field must be defined as a valid suffix
-		 * (or suffixAlias?) for the current database;
-		 * the <massaged suffix> shouldn't have already been
-		 * defined as a valid suffix or suffixAlias for the
-		 * current server
-		 */
+	case LDAP_BACK_CFG_SUFFIXM:	/* FALLTHRU */
+	case LDAP_BACK_CFG_REWRITE: {
+	/* rewrite stuff ... */
+		ConfigArgs ca = { 0 };
+		char *line, **argv;
+		struct rewrite_info *rwi;
+		int cnt = 0, argc, ix = c->valx;
 
-		ber_str2bv( c->argv[ 1 ], 0, 0, &dn );
-		if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"suffix \"%s\" is invalid",
-				c->argv[1] );
-			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
-			return 1;
+		if ( mt->mt_rwmap.rwm_bva_rewrite ) {
+			for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_rewrite[ cnt ] ); cnt++ )
+				/* count */ ;
 		}
 
-		for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
-			if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) {
-				break;
+		if ( ix >= cnt || ix < 0 ) {
+			ix = cnt;
+		} else {
+			rwi = mt->mt_rwmap.rwm_rw;
+
+			mt->mt_rwmap.rwm_rw = NULL;
+			rc = meta_rwi_init( &mt->mt_rwmap.rwm_rw );
+
+			/* re-parse all rewrite rules, up to the one
+			 * that needs to be added */
+			ca.fname = c->fname;
+			ca.lineno = c->lineno;
+			for ( i = 0; i < ix; i++ ) {
+				ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
+				ca.argc = 0;
+				config_fp_parse_line( &ca );
+
+				if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
+					rc = meta_suffixm_config( &ca, mt );
+				} else {
+					rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
+						c->fname, c->lineno, ca.argc, argv );
+				}
+				assert( rc == 0 );
+				ch_free( ca.argv );
+				ch_free( ca.tline );
 			}
 		}
-
-		if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"suffix \"%s\" must be within the database naming context",
-				c->argv[1] );
-			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
-			free( pvnc.bv_val );
-			free( nvnc.bv_val );
-			return 1;
+		argc = c->argc;
+		argv = c->argv;
+		/* add the new rule */
+		if ( c->type == LDAP_BACK_CFG_SUFFIXM ) {
+			rc = meta_suffixm_config( c, mt );
+		} else {
+			if ( c->op != SLAP_CONFIG_ADD ) {
+				argc--;
+				argv++;
+			}
+			rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
+						c->fname, c->lineno, argc, argv );
 		}
-
-		ber_str2bv( c->argv[ 2 ], 0, 0, &dn );
-		if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"massaged suffix \"%s\" is invalid",
-				c->argv[2] );
-			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
-			free( pvnc.bv_val );
-			free( nvnc.bv_val );
+		if ( rc ) {
+			if ( ix < cnt ) {
+				rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
+				mt->mt_rwmap.rwm_rw = rwi;
+			}
 			return 1;
 		}
+		if ( ix < cnt ) {
+			for ( ; i < cnt; i++ ) {
+				ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
+				ca.argc = 0;
+				config_fp_parse_line( &ca );
+
+				if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
+					rc = meta_suffixm_config( &ca, mt );
+				} else {
+					rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
+						c->fname, c->lineno, ca.argc, argv );
+				}
+				assert( rc == 0 );
+				ch_free( ca.argv );
+				ch_free( ca.tline );
+			}
+		}
 
-		tmp_bd = select_backend( &nrnc, 0 );
-		if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) {
-			Debug( LDAP_DEBUG_ANY,
-	"%s: warning: <massaged suffix> \"%s\" resolves to this database, in "
-	"\"suffixMassage <suffix> <massaged suffix>\"\n",
-				c->log, prnc.bv_val, 0 );
+		/* save the rule info */
+		line = ldap_charray2str( argv, "\" \"" );
+		if ( line != NULL ) {
+			struct berval bv;
+			int len = strlen( argv[ 0 ] );
+
+			ber_str2bv( line, 0, 0, &bv );
+			AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
+				bv.bv_len - ( len + 1 ));
+			bv.bv_val[ bv.bv_len - 1] = '"';
+			ber_bvarray_add( &mt->mt_rwmap.rwm_bva_rewrite, &bv );
+			/* move it to the right slot */
+			if ( ix < cnt ) {
+				for ( i=cnt; i>ix; i-- )
+					mt->mt_rwmap.rwm_bva_rewrite[i+1] = mt->mt_rwmap.rwm_bva_rewrite[i];
+				mt->mt_rwmap.rwm_bva_rewrite[i] = bv;
+
+				/* destroy old rules */
+				rewrite_info_delete( &rwi );
+			}
 		}
+		} break;
 
-		/*
-		 * The suffix massaging is emulated by means of the
-		 * rewrite capabilities
-		 */
-		rc = suffix_massage_config( mt->mt_rwmap.rwm_rw,
-				&pvnc, &nvnc, &prnc, &nrnc );
+	case LDAP_BACK_CFG_MAP: {
+	/* objectclass/attribute mapping */
+		ConfigArgs ca = { 0 };
+		char *argv[5];
+		struct ldapmap rwm_oc;
+		struct ldapmap rwm_at;
+		int cnt = 0, ix = c->valx;
 
-		free( pvnc.bv_val );
-		free( nvnc.bv_val );
-		free( prnc.bv_val );
-		free( nrnc.bv_val );
+		if ( mt->mt_rwmap.rwm_bva_map ) {
+			for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_map[ cnt ] ); cnt++ )
+				/* count */ ;
+		}
 
-		return rc;
+		if ( ix >= cnt || ix < 0 ) {
+			ix = cnt;
+		} else {
+			rwm_oc = mt->mt_rwmap.rwm_oc;
+			rwm_at = mt->mt_rwmap.rwm_at;
+
+			memset( &mt->mt_rwmap.rwm_oc, 0, sizeof( mt->mt_rwmap.rwm_oc ) );
+			memset( &mt->mt_rwmap.rwm_at, 0, sizeof( mt->mt_rwmap.rwm_at ) );
+
+			/* re-parse all mappings, up to the one
+			 * that needs to be added */
+			argv[0] = c->argv[0];
+			ca.fname = c->fname;
+			ca.lineno = c->lineno;
+			for ( i = 0; i < ix; i++ ) {
+				ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
+				ca.argc = 0;
+				config_fp_parse_line( &ca );
+
+				argv[1] = ca.argv[0];
+				argv[2] = ca.argv[1];
+				argv[3] = ca.argv[2];
+				argv[4] = ca.argv[3];
+				ch_free( ca.argv );
+				ca.argv = argv;
+				ca.argc++;
+				rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
+					&mt->mt_rwmap.rwm_at );
+
+				ch_free( ca.tline );
+				ca.tline = NULL;
+				ca.argv = NULL;
+
+				/* in case of failure, restore
+				 * the existing mapping */
+				if ( rc ) {
+					goto map_fail;
+				}
+			}
+		}
+		/* add the new mapping */
+		rc = ldap_back_map_config( c, &mt->mt_rwmap.rwm_oc,
+					&mt->mt_rwmap.rwm_at );
+		if ( rc ) {
+			goto map_fail;
+		}
+
+		if ( ix < cnt ) {
+			for ( ; i<cnt ; cnt++ ) {
+				ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
+				ca.argc = 0;
+				config_fp_parse_line( &ca );
+
+				argv[1] = ca.argv[0];
+				argv[2] = ca.argv[1];
+				argv[3] = ca.argv[2];
+				argv[4] = ca.argv[3];
+
+				ch_free( ca.argv );
+				ca.argv = argv;
+				ca.argc++;
+				rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
+					&mt->mt_rwmap.rwm_at );
+
+				ch_free( ca.tline );
+				ca.tline = NULL;
+				ca.argv = NULL;
+
+				/* in case of failure, restore
+				 * the existing mapping */
+				if ( rc ) {
+					goto map_fail;
+				}
+			}
 		}
 
-	case LDAP_BACK_CFG_REWRITE:
-	/* rewrite stuff ... */
-		return rewrite_parse( mt->mt_rwmap.rwm_rw,
-				c->fname, c->lineno, c->argc, c->argv );
+		/* save the map info */
+		argv[0] = ldap_charray2str( &c->argv[ 1 ], " " );
+		if ( argv[0] != NULL ) {
+			struct berval bv;
+			ber_str2bv( argv[0], 0, 0, &bv );
+			ber_bvarray_add( &mt->mt_rwmap.rwm_bva_map, &bv );
+			/* move it to the right slot */
+			if ( ix < cnt ) {
+				for ( i=cnt; i>ix; i-- )
+					mt->mt_rwmap.rwm_bva_map[i+1] = mt->mt_rwmap.rwm_bva_map[i];
+				mt->mt_rwmap.rwm_bva_map[i] = bv;
+
+				/* destroy old mapping */
+				meta_back_map_free( &rwm_oc );
+				meta_back_map_free( &rwm_at );
+			}
+		}
+		break;
 
-	case LDAP_BACK_CFG_MAP:
-	/* objectclass/attribute mapping */
-		return ldap_back_map_config( c, &mt->mt_rwmap.rwm_oc,
-				&mt->mt_rwmap.rwm_at );
+map_fail:;
+		if ( ix < cnt ) {
+			meta_back_map_free( &mt->mt_rwmap.rwm_oc );
+			meta_back_map_free( &mt->mt_rwmap.rwm_at );
+			mt->mt_rwmap.rwm_oc = rwm_oc;
+			mt->mt_rwmap.rwm_at = rwm_at;
+		}
+		} break;
 
 	case LDAP_BACK_CFG_NRETRIES: {
 		int		nretries = META_RETRY_UNDEFINED;
diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c
index 28e58c9180fb2b72b8a2ec5829e87461c0f5910e..dcd6c854a60a2a3c7da5fdc209d3ff8d76d1fc31 100644
--- a/servers/slapd/back-meta/init.c
+++ b/servers/slapd/back-meta/init.c
@@ -311,6 +311,13 @@ mapping_dst_free(
 	}
 }
 
+void
+meta_back_map_free( struct ldapmap *lm )
+{
+	avl_free( lm->remap, mapping_dst_free );
+	avl_free( lm->map, mapping_free );
+}
+
 static void
 target_free(
 	metatarget_t	*mt )
@@ -358,11 +365,12 @@ target_free(
 	}
 	if ( mt->mt_rwmap.rwm_rw ) {
 		rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
+		if ( mt->mt_rwmap.rwm_bva_rewrite )
+			ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
 	}
-	avl_free( mt->mt_rwmap.rwm_oc.remap, mapping_dst_free );
-	avl_free( mt->mt_rwmap.rwm_oc.map, mapping_free );
-	avl_free( mt->mt_rwmap.rwm_at.remap, mapping_dst_free );
-	avl_free( mt->mt_rwmap.rwm_at.map, mapping_free );
+	meta_back_map_free( &mt->mt_rwmap.rwm_oc );
+	meta_back_map_free( &mt->mt_rwmap.rwm_at );
+	ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
 
 	free( mt );
 }