diff --git a/doc/man/man5/slapo-refint.5 b/doc/man/man5/slapo-refint.5
new file mode 100644
index 0000000000000000000000000000000000000000..803e00ccb1e29013710c442a4ba1c65552f6bbd8
--- /dev/null
+++ b/doc/man/man5/slapo-refint.5
@@ -0,0 +1,53 @@
+.TH SLAPO-REFINT 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2004 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapo-refint \- Referential Integrity overlay
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The Referential Integrity overlay can be used with a backend database such as
+.BR slapd-bdb (5)
+to maintain the cohesiveness of a schema which utilizes reference attributes.
+.LP
+Integrity is maintained by updating database records which contain the named
+attributes to match the results of a
+.B modrdn
+or
+.B delete
+operation. For example, if the integrity attribute were configured as
+.B manager ,
+deletion of the record "uid=robert,ou=people,o=openldap.org" would trigger a
+search for all other records which have a
+.B manager
+attribute containing that DN. Entries matching that search would have their
+.B manager
+attribute removed.
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the Referential Integrity overlay.
+They should appear after the
+.B overlay
+directive and before any subsequent
+.B database
+directive.
+.TP
+.B refint_attributes <attribute...>
+Specify one or more attributes which for which integrity will be maintained
+as described above.
+.TP
+.B refint_nothing <string>
+Specify an arbitrary value to be used as a placeholder when the last value
+would otherwise be deleted from an attribute. This can be useful in cases
+where the schema requires the existence of an attribute for which referential
+integrity is enforced. The attempted deletion of a required attribute will
+otherwise result in an Object Class Violation, causing the request to fail.
+.B
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5).
diff --git a/doc/man/man5/slapo-unique.5 b/doc/man/man5/slapo-unique.5
new file mode 100644
index 0000000000000000000000000000000000000000..8a1026945070d3da1ccfaa34df7531c55f16babf
--- /dev/null
+++ b/doc/man/man5/slapo-unique.5
@@ -0,0 +1,93 @@
+.TH SLAPO-UNIQUE 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2004 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapo-unique \- Attribute Uniqueness overlay
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The Attribute Uniqueness overlay can be used with a backend database such as
+.BR slapd-bdb (5)
+to enforce the uniqueness of some or all attributes within a subtree. This
+subtree defaults to the base DN of the database for which the Uniqueness
+overlay is configured.
+.LP
+Uniqueness is enforced by searching the subtree to ensure that the values of
+all attributes presented with an
+.B add ,
+.B modify
+or
+.B modrdn
+operation are unique within the subtree.
+For example, if uniquness were enforced for the
+.B uid
+attribute, the subtree would be searched for any other records which also
+have a
+.B uid
+attribute containing the same value. If any are found, the request is
+rejected.
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the Attribute Uniqueness overlay.
+They should appear after the
+.B overlay
+directive and before any subsequent
+.B database
+directive.
+.TP
+.B unique_base <basedn>
+Configure the subtree against which uniqueness searches will be invoked.
+The
+.B basedn
+defaults to the base DN of the database for which uniqueness is configured.
+.TP
+.B unique_ignore <attribute...>
+Configure one or more attributes for which uniqueness will not be enforced.
+If not configured, all non-operational (eg, system) attributes must be
+unique. Note that the
+.B unique_ignore
+list should generally contain the
+.B objectClass ,
+.B dc ,
+.B ou
+and
+.B o
+attributes, as these will generally not be unique, nor are they operational
+attributes.
+.TP
+.B unique_attributes <attribute...>
+Specify one or more attributes which for which uniqueness will be enforced.
+If not specified, all attributes which are not operational (eg, system
+attributes such as
+.B entryUUID )
+or specified via the
+.B unique_ignore
+directive above must be unique within the subtree.
+.TP
+.B unique_strict
+By default, uniqueness is not enforced for null values. Enabling
+.B unique_strict
+mode extends the concept of uniqueness to include null values, such that
+only one attribute within a subtree will be allowed to have a null value.
+.SH CAVEATS
+.LP
+The search key is generated with attributes that are non-operational, not
+on the
+.B unique_ignore
+list, and included in the
+.B unique_attributes
+list, in that order. This makes it possible to create interesting and
+unusable configurations.
+.LP
+Typical attributes for the
+.B unique_ignore
+directive are intentionally not hardcoded into the overlay to allow for
+maximum flexibility in meeting site-specific requirements.
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5).
diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in
index 71f26f88e0b471dc79bc1ade39a056b8d2c4516f..1a201973d122e897a4e7428355200bf7e7513551 100644
--- a/servers/slapd/overlays/Makefile.in
+++ b/servers/slapd/overlays/Makefile.in
@@ -19,6 +19,8 @@ SRCS = overlays.c \
 	dyngroup.c \
 	lastmod.c \
 	pcache.c \
+	refint.c \
+	unique.c \
 	rwm.c rwmconf.c rwmdn.c rwmmap.c
 OBJS = overlays.lo \
 	chain.lo \
@@ -26,6 +28,8 @@ OBJS = overlays.lo \
 	dyngroup.lo \
 	lastmod.lo \
 	pcache.lo \
+	refint.lo \
+	unique.lo \
 	rwm.lo rwmconf.lo rwmdn.lo rwmmap.lo
 
 LDAP_INCDIR= ../../../include       
@@ -58,6 +62,12 @@ lastmod.la : lastmod.lo $(@PLAT@_LINK_LIBS)
 pcache.la : pcache.lo $(@PLAT@_LINK_LIBS)
 	$(LTLINK_MOD) -module -o $@ pcache.lo version.lo $(LINK_LIBS)
 
+refint.la : refint.lo $(@PLAT@_LINK_LIBS)
+	$(LTLINK_MOD) -module -o $@ refint.lo version.lo $(LINK_LIBS)
+
+unique.la : unique.lo $(@PLAT@_LINK_LIBS)
+	$(LTLINK_MOD) -module -o $@ unique.lo version.lo $(LINK_LIBS)
+
 rwm.la : rwm.lo $(@PLAT@_LINK_LIBS)
 	$(LTLINK_MOD) -module -o $@ rwm.lo rwmconf.lo rwmdn.lo rwmmap.lo version.lo $(LINK_LIBS)
 
diff --git a/servers/slapd/overlays/refint.c b/servers/slapd/overlays/refint.c
new file mode 100644
index 0000000000000000000000000000000000000000..d97f49dce47d1139dc8813e4e4bd7d4340d1c614
--- /dev/null
+++ b/servers/slapd/overlays/refint.c
@@ -0,0 +1,675 @@
+/* refint.c - referential integrity module */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2004 The OpenLDAP Foundation.
+ * Portions Copyright 2004 Symas Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Symas Corp. for inclusion in
+ * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
+ */
+
+#include "portable.h"
+
+/* This module maintains referential integrity for a set of
+ * DN-valued attributes by searching for all references to a given
+ * DN whenever the DN is changed or its entry is deleted, and making
+ * the appropriate update.
+ *
+ * Updates are performed using the database rootdn, but the ModifiersName
+ * is always set to refint_dn.
+ */
+
+#ifdef SLAPD_OVER_REFINT
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+static slap_overinst refint;
+
+/* The DN to use in the ModifiersName for all refint updates */
+static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay");
+
+typedef struct refint_attrs_s {
+	struct refint_attrs_s *next;
+	AttributeDescription *attr;
+} refint_attrs;
+
+typedef struct dependents_s {
+	struct dependents_s *next;
+	BerValue dn;				/* target dn */
+	Modifications *mm;
+} dependent_data;
+
+typedef struct refint_data_s {
+	const char *message;			/* breadcrumbs */
+	struct refint_attrs_s *attrs;	/* list of known attrs */
+	struct dependents_s *mods;		/* modifications returned from callback */
+	BerValue dn;				/* basedn in parent, searchdn in call */
+	BerValue newdn;				/* replacement value for modrdn callback */
+	BerValue nnewdn;			/* normalized replacement value */
+	BerValue nothing;			/* the nothing value, if needed */
+	BerValue nnothing;			/* normalized nothingness */
+} refint_data;
+
+/*
+** allocate new refint_data;
+** initialize, copy basedn;
+** store in on_bi.bi_private;
+**
+*/
+
+static int
+refint_db_init(
+	BackendDB	*be
+)
+{
+	slap_overinst *on = (slap_overinst *)be->bd_info;
+	refint_data *id = ch_malloc(sizeof(refint_data));
+	refint_attrs *ip;
+	id->message = "_init";
+	id->attrs = NULL;
+	id->newdn.bv_val = NULL;
+	id->nothing.bv_val = NULL;
+	id->nnothing.bv_val = NULL;
+	ber_dupbv( &id->dn, &be->be_nsuffix[0] );
+	on->on_bi.bi_private = id;
+	return(0);
+}
+
+
+/*
+** if command = attributes:
+**	foreach argument:
+**		convert to attribute;
+**		add to configured attribute list;
+** elseif command = basedn:
+**	set our basedn to argument;
+**
+*/
+
+static int
+refint_config(
+	BackendDB	*be,
+	const char	*fname,
+	int		lineno,
+	int		argc,
+	char		**argv
+)
+{
+	slap_overinst *on	= (slap_overinst *) be->bd_info;
+	refint_data *id	= on->on_bi.bi_private;
+	refint_attrs *ip;
+	const char *text;
+	AttributeDescription *ad;
+	BerValue dn;
+	int i;
+
+	if(!strcasecmp(*argv, "refint_attributes")) {
+		for(i = 1; i < argc; i++) {
+			for(ip = id->attrs; ip; ip = ip->next)
+			    if(!strcmp(argv[i], ip->attr->ad_cname.bv_val)) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: duplicate attribute <s>, ignored\n",
+					fname, lineno, argv[i]);
+				continue;
+			}
+			ad = NULL;
+			if(slap_str2ad(argv[i], &ad, &text) != LDAP_SUCCESS) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: bad attribute <%s>, ignored\n",
+					fname, lineno, text);
+				continue;		/* XXX */
+			} else if(ad->ad_next) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: multiple attributes match <%s>, ignored\n",
+					fname, lineno, argv[i]);
+				continue;
+			}
+			ip = ch_malloc(sizeof(refint_attrs));
+			ip->attr = ad;
+			ip->next = id->attrs;
+			id->attrs = ip;
+			Debug(LDAP_DEBUG_ANY, "%s: line %d: new attribute <%s>\n",
+				fname, lineno, argv[i]);
+		}
+	} else if(!strcasecmp(*argv, "refint_base")) {
+		/* XXX only one basedn (yet) - need validate argument! */
+		if(id->dn.bv_val) ch_free(id->dn.bv_val);
+		ber_str2bv( argv[1], 0, 0, &dn );
+		Debug(LDAP_DEBUG_ANY, "%s: line %d: new baseDN <%s>\n",
+			fname, lineno, argv[1]);
+		if(dnNormalize(0, NULL, NULL, &dn, &id->dn, NULL)) {
+			Debug(LDAP_DEBUG_ANY, "%s: line %d: bad baseDN!\n", fname, lineno, 0);
+			return(1);
+		}
+	} else if(!strcasecmp(*argv, "refint_nothing")) {
+		if(id->nothing.bv_val) ch_free(id->nothing.bv_val);
+		if(id->nnothing.bv_val) ch_free(id->nnothing.bv_val);
+		ber_str2bv( argv[1], 0, 1, &id->nothing );
+		if(dnNormalize(0, NULL, NULL, &id->nothing, &id->nnothing, NULL)) {
+			Debug(LDAP_DEBUG_ANY, "%s: line %d: bad nothingDN!\n", fname, lineno, 0);
+			return(1);
+		}
+		Debug(LDAP_DEBUG_ANY, "%s: line %d: new nothingDN<%s>\n",
+			fname, lineno, argv[1]);
+	} else {
+		return(SLAP_CONF_UNKNOWN);
+	}
+
+	id->message = "_config";
+	return(0);
+}
+
+
+/*
+** nothing really happens here;
+**
+*/
+
+static int
+refint_open(
+	BackendDB *be
+)
+{
+	slap_overinst *on	= (slap_overinst *)be->bd_info;
+	refint_data *id	= on->on_bi.bi_private;
+	id->message		= "_open";
+	return(0);
+}
+
+
+/*
+** foreach configured attribute:
+**	free it;
+** free our basedn;
+** (do not) free id->message;
+** reset on_bi.bi_private;
+** free our config data;
+**
+*/
+
+static int
+refint_close(
+	BackendDB *be
+)
+{
+	slap_overinst *on	= (slap_overinst *) be->bd_info;
+	refint_data *id	= on->on_bi.bi_private;
+	refint_attrs *ii, *ij;
+	id->message		= "_close";
+
+	for(ii = id->attrs; ii; ii = ij) {
+		ij = ii->next;
+		ch_free(ii);
+	}
+
+	ch_free(id->dn.bv_val);
+	ch_free(id->nothing.bv_val);
+	ch_free(id->nnothing.bv_val);
+
+	on->on_bi.bi_private = NULL;	/* XXX */
+
+	ch_free(id);
+
+	return(0);
+}
+
+/*
+** delete callback
+** generates a list of Modification* from search results
+*/
+
+static int
+refint_delete_cb(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Attribute *a;
+	BerVarray b = NULL;
+	refint_data *id, *dd = op->o_callback->sc_private;
+	refint_attrs *ia, *da = dd->attrs;
+	dependent_data *ip, *dp = NULL;
+	Modifications *mp, *ma;
+	int i;
+
+	Debug(LDAP_DEBUG_TRACE, "refint_delete_cb <%s>\n",
+		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);
+
+	if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
+	dd->message = "_delete_cb";
+
+	/*
+	** foreach configured attribute type:
+	**	if this attr exists in the search result,
+	**	and it has a value matching the target:
+	**		allocate a Modification;
+	**		allocate its array of 2 BerValues;
+	**		if only one value, and we have a configured Nothing:
+	**			allocate additional Modification
+	**			type = MOD_ADD
+	**			BerValues[] = { Nothing, NULL };
+	**			add to list
+	**		type = MOD_DELETE
+	**		BerValues[] = { our target dn, NULL };
+	**	add this mod to the list of mods;
+	**
+	*/
+
+	ip = ch_malloc(sizeof(dependent_data));
+	ip->dn.bv_val = NULL;
+	ip->next = NULL;
+	ip->mm = NULL;
+	ma = NULL;
+	for(ia = da; ia; ia = ia->next) {
+	    if(a = attr_find(rs->sr_entry->e_attrs, ia->attr))
+		for(i = 0, b = a->a_nvals; b[i].bv_val; i++)
+		    if(bvmatch(&dd->dn, &b[i])) {
+			if(!ip->dn.bv_val) ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
+			if(!b[1].bv_val && dd->nothing.bv_val) {
+				mp = ch_malloc(sizeof(Modifications));
+				mp->sml_desc = ia->attr;		/* XXX */
+				mp->sml_type = a->a_desc->ad_cname;
+				mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
+				mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
+				mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
+				mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
+
+				mp->sml_op = LDAP_MOD_ADD;
+				ber_dupbv(&mp->sml_values[0],  &dd->nothing);
+				ber_dupbv(&mp->sml_nvalues[0], &dd->nnothing);
+				mp->sml_next = ma;
+				ma = mp;
+			}
+		 	/* this might violate the object class */
+			mp = ch_malloc(sizeof(Modifications));
+			mp->sml_desc = ia->attr;		/* XXX */
+			mp->sml_type = a->a_desc->ad_cname;
+			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
+			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
+			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
+			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
+			mp->sml_op = LDAP_MOD_DELETE;
+			ber_dupbv(&mp->sml_values[0], &dd->dn);
+			ber_dupbv(&mp->sml_nvalues[0], &mp->sml_values[0]);
+			mp->sml_next = ma;
+			ma = mp;
+			Debug(LDAP_DEBUG_TRACE, "refint_delete_cb: %s: %s\n",
+				a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
+			break;
+	    }
+	}
+	ip->mm = ma;
+	ip->next = dd->mods;
+	dd->mods = ip;
+
+	return(0);
+}
+
+/*
+** null callback
+** does nothing
+*/
+
+static int
+refint_null_cb(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	((refint_data *)op->o_callback->sc_private)->message = "_null_cb";
+	return(LDAP_SUCCESS);
+}
+
+/*
+** modrdn callback
+** generates a list of Modification* from search results
+*/
+
+static int
+refint_modrdn_cb(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Attribute *a;
+	BerVarray b = NULL;
+	refint_data *id, *dd = op->o_callback->sc_private;
+	refint_attrs *ia, *da = dd->attrs;
+	dependent_data *ip = NULL, *dp = NULL;
+	Modifications *mp;
+	int i, j, fix;
+
+	Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb <%s>\n",
+		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);
+
+	if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
+	dd->message = "_modrdn_cb";
+
+	/*
+	** foreach configured attribute type:
+	**   if this attr exists in the search result,
+	**   and it has a value matching the target:
+	**	allocate a pair of Modifications;
+	**	make it MOD_ADD the new value and MOD_DELETE the old;
+	**	allocate its array of BerValues;
+	**	foreach value in the search result:
+	**	   if it matches our target value, replace it;
+	**	   otherwise, copy from the search result;
+	**	terminate the array of BerValues;
+	**   add these mods to the list of mods;
+	**
+	*/
+
+	for(ia = da; ia; ia = ia->next) {
+	    if(a = attr_find(rs->sr_entry->e_attrs, ia->attr)) {
+		    for(fix = 0, i = 0, b = a->a_nvals; b[i].bv_val; i++)
+			if(bvmatch(&dd->dn, &b[i])) { fix++; break; }
+		    if(fix) {
+			if (!ip) {
+	    		    ip = ch_malloc(sizeof(dependent_data));
+	    		    ip->next = NULL;
+	    		    ip->mm = NULL;
+	    		    ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
+			}
+			mp = ch_malloc(sizeof(Modifications));
+			mp->sml_op = LDAP_MOD_ADD;
+			mp->sml_desc = ia->attr;		/* XXX */
+			mp->sml_type = ia->attr->ad_cname;
+			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
+			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
+			ber_dupbv(&mp->sml_values[0], &dd->newdn);
+			ber_dupbv(&mp->sml_nvalues[0], &dd->nnewdn);
+			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
+			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
+			mp->sml_next = ip->mm;
+			ip->mm = mp;
+			mp = ch_malloc(sizeof(Modifications));
+			mp->sml_op = LDAP_MOD_DELETE;
+			mp->sml_desc = ia->attr;		/* XXX */
+			mp->sml_type = ia->attr->ad_cname;
+			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
+			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
+			ber_dupbv(&mp->sml_values[0], &dd->dn);
+			ber_dupbv(&mp->sml_nvalues[0], &dd->dn);
+			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
+			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
+			mp->sml_next = ip->mm;
+			ip->mm = mp;
+			Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb: %s: %s\n",
+				a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
+		}
+	    }
+	}
+	if (ip) {
+		ip->next = dd->mods;
+		dd->mods = ip;
+	}
+
+	return(0);
+}
+
+
+/*
+** refint_response
+** search for matching records and modify them
+*/
+
+static int
+refint_response(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Operation nop = *op;
+	SlapReply nrs = { REP_RESULT };
+	slap_callback cb = { NULL, NULL, NULL, NULL };
+	slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL };
+	slap_callback *cbo, *cbp;
+	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+	refint_data *id = on->on_bi.bi_private;
+	refint_data dd = *id;
+	refint_attrs *ip;
+	dependent_data *dp;
+	char *fstr, *key, *kp, **dnpp, **ndnpp, *cp;
+	BerValue ndn, moddn, pdn;
+	BerVarray b = NULL;
+	int rc, ac, i, j, ksize;
+
+	id->message = "_refint_response";
+
+	/* If the main op failed or is not a Delete or ModRdn, ignore it */
+	if (( op->o_tag != LDAP_REQ_DELETE && op->o_tag != LDAP_REQ_MODRDN ) ||
+		rs->sr_err != LDAP_SUCCESS )
+		return SLAP_CB_CONTINUE;
+
+	/*
+	** validate (and count) the list of attrs;
+	**
+	*/
+
+	for(ip = id->attrs, ac = 0; ip; ip = ip->next, ac++);
+	if(!ac) {
+		rs->sr_err = LDAP_OTHER;
+		rs->sr_text = "refint_response called without any attributes";
+		return SLAP_CB_CONTINUE;
+	}
+
+	/*
+	** find the backend that matches our configured basedn;
+	** make sure it exists and has search and modify methods;
+	**
+	*/
+
+	nop.o_bd = select_backend(&id->dn, 0, 1);
+
+	if(nop.o_bd) {
+		if (!nop.o_bd->be_search || !nop.o_bd->be_modify) {
+			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+			rs->sr_text = "backend missing search and/or modify";
+			return SLAP_CB_CONTINUE;
+		}
+	} else {
+		rs->sr_err = LDAP_OTHER;
+		rs->sr_text = "no known backend? this shouldn't be happening!";
+		return SLAP_CB_CONTINUE;
+	}
+
+	cb2.sc_next = &cb;
+
+	/*
+	** if delete: set delete callback;
+	** else modrdn: create a newdn, set modify callback;
+	**
+	*/
+
+	if(op->o_tag == LDAP_REQ_DELETE) {
+		cb.sc_response = &refint_delete_cb;
+		dd.newdn.bv_val = NULL;
+		dd.nnewdn.bv_val = NULL;
+	} else {
+		cb.sc_response = &refint_modrdn_cb;
+		if ( op->oq_modrdn.rs_newSup ) {
+			pdn = *op->oq_modrdn.rs_newSup;
+		} else {
+			dnParent( &op->o_req_dn, &pdn );
+		}
+		build_new_dn( &dd.newdn, &pdn, &op->orr_newrdn, NULL );
+		if ( op->oq_modrdn.rs_nnewSup ) {
+			pdn = *op->oq_modrdn.rs_nnewSup;
+		} else {
+			dnParent( &op->o_req_ndn, &pdn );
+		}
+		build_new_dn( &dd.nnewdn, &pdn, &op->orr_nnewrdn, NULL );
+	}
+
+	/*
+	** calculate the search key size and allocate it;
+	** build a search filter for all configured attributes;
+	** populate our Operation;
+	** pass our data (attr list, dn) to backend via sc_private;
+	** call the backend search function;
+	** nb: (|(one=thing)) is valid, but do smart formatting anyway;
+	** nb: 16 is arbitrarily a dozen or so extra bytes;
+	**
+	*/
+
+	for(ksize = 16, ip = id->attrs; ip; ip = ip->next)
+		ksize += ip->attr->ad_cname.bv_len + op->o_req_dn.bv_len + 3;
+	kp = key = ch_malloc(ksize);
+	if(--ac) kp += sprintf(key, "(|");
+	for(ip = id->attrs; ip; ip = ip->next)
+		kp += sprintf(kp, "(%s=%s)",
+			ip->attr->ad_cname.bv_val, op->o_req_dn.bv_val);
+	if(ac) *kp++ = ')';
+	*kp = 0;
+
+	nop.ors_filter = str2filter_x(&nop, key);
+	ber_str2bv(key, 0, 0, &nop.ors_filterstr);
+
+	/* callback gets the searched dn instead */
+	dd.dn = op->o_req_ndn;
+	dd.message	= "_dependent_search";
+	dd.mods		= NULL;
+	cb.sc_private	= &dd;
+	nop.o_callback	= &cb;
+	nop.o_tag	= LDAP_REQ_SEARCH;
+	nop.ors_scope	= LDAP_SCOPE_SUBTREE;
+	nop.ors_deref	= LDAP_DEREF_NEVER;
+	nop.ors_slimit	= -1;
+	nop.ors_tlimit	= -1;
+	nop.o_req_ndn = id->dn;
+	nop.o_req_dn = id->dn;
+
+	/* search */
+	rc = nop.o_bd->be_search(&nop, &nrs);
+
+	filter_free_x(&nop, nop.ors_filter);
+	ch_free(key);
+	ch_free(dd.nnewdn.bv_val);
+	ch_free(dd.newdn.bv_val);
+	dd.newdn.bv_val	= NULL;
+	dd.nnewdn.bv_val = NULL;
+
+	if(rc != LDAP_SUCCESS) {
+		rs->sr_err = nrs.sr_err;
+		rs->sr_text = "refint_response search failed";
+		goto done;
+	}
+
+	/* safety? paranoid just in case */
+	if(!cb.sc_private) {
+		rs->sr_err = LDAP_OTHER;
+		rs->sr_text = "whoa! refint_response callback wiped out sc_private?!";
+		goto done;
+	}
+
+	/* presto! now it's a modify request with null callback */
+	cb.sc_response	= &refint_null_cb;
+	nop.o_tag	= LDAP_REQ_MODIFY;
+	dd.message	= "_dependent_modify";
+
+	/* See if the parent operation is going into the replog */
+	cbo = NULL;
+	for (cbp = op->o_callback->sc_next; cbp; cbo=cbp,cbp=cbp->sc_next) {
+		if (cbp->sc_response == slap_replog_cb) {
+			/* Invoke replog now, arrange for our
+			 * dependent mods to also be logged
+			 */
+			cbo->sc_next = cbp->sc_next;
+			replog( op );
+			nop.o_callback = &cb2;
+			break;
+		}
+	}
+
+	/*
+	** [our search callback builds a list of mods]
+	** foreach mod:
+	**	make sure its dn has a backend;
+	**	connect Modification* chain to our op;
+	**	call the backend modify function;
+	**	pass any errors upstream;
+	**
+	*/
+
+	for(dp = dd.mods; dp; dp = dp->next) {
+		Modifications **tail, *m;
+
+		for(m = dp->mm; m && m->sml_next; m = m->sml_next);
+		tail = &m->sml_next;
+		nop.o_req_dn	= dp->dn;
+		nop.o_req_ndn	= dp->dn;
+		nop.o_bd = select_backend(&dp->dn, 0, 1);
+		if(!nop.o_bd) {
+			rs->sr_err = LDAP_OTHER;
+			rs->sr_text = "this should never happen either!";
+			goto done;
+		}
+		nrs.sr_type	= REP_RESULT;
+		nop.orm_modlist = dp->mm;	/* callback did all the work */
+		nop.o_dn = refint_dn;
+		nop.o_ndn = refint_dn;
+		rs->sr_err = slap_mods_opattrs( &nop, nop.orm_modlist,
+			tail, &rs->sr_text, NULL, 0 );
+		nop.o_dn = nop.o_bd->be_rootdn;
+		nop.o_ndn = nop.o_bd->be_rootndn;
+		if(rs->sr_err != LDAP_SUCCESS) goto done;
+		if((rc = nop.o_bd->be_modify(&nop, &nrs)) != LDAP_SUCCESS) {
+			rs->sr_err = nrs.sr_err;
+			rs->sr_text = "dependent modify failed";
+			goto done;
+		}
+	}
+
+done:
+	for(dp = dd.mods; dp; dp = dd.mods) {
+		dd.mods = dp->next;
+		ch_free(dp->dn.bv_val);
+		slap_mods_free(dp->mm);
+	}
+	dd.mods = NULL;
+
+	return(SLAP_CB_CONTINUE);
+}
+
+/*
+** init_module is last so the symbols resolve "for free" --
+** it expects to be called automagically during dynamic module initialization
+*/
+
+int refint_init() {
+
+	/* statically declared just after the #includes at top */
+	refint.on_bi.bi_type = "refint";
+	refint.on_bi.bi_db_init = refint_db_init;
+	refint.on_bi.bi_db_config = refint_config;
+	refint.on_bi.bi_db_open = refint_open;
+	refint.on_bi.bi_db_close = refint_close;
+	refint.on_response = refint_response;
+
+	return(overlay_register(&refint));
+}
+
+#if SLAPD_OVER_REFINT == SLAPD_MOD_DYNAMIC && defined(PIC)
+int init_module(int argc, char *argv[]) {
+	return refint_init();
+}
+#endif
+
+#endif /* SLAPD_OVER_REFINT */
diff --git a/servers/slapd/overlays/unique.c b/servers/slapd/overlays/unique.c
new file mode 100644
index 0000000000000000000000000000000000000000..4fe528d8dfe9dbe2272619282c636dcfcdb4f808
--- /dev/null
+++ b/servers/slapd/overlays/unique.c
@@ -0,0 +1,669 @@
+/* unique.c - attribute uniqueness module */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2004 The OpenLDAP Foundation.
+ * Portions Copyright 2004 Symas Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Symas Corp. for inclusion in
+ * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_UNIQUE
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+static slap_overinst unique;
+
+typedef struct unique_attrs_s {
+	struct unique_attrs_s *next;		/* list of attrs */
+	AttributeDescription *attr;
+} unique_attrs;
+
+typedef struct unique_data_s {
+	const char *message;			/* breadcrumbs */
+	struct unique_attrs_s *attrs;		/* list of known attrs */
+	struct unique_attrs_s *ignore;		/* list of ignored attrs */
+	BerValue dn;				/* base of "unique tree" */
+	char strict;				/* null considered unique too */
+} unique_data;
+
+typedef struct unique_counter_s {
+	int count;
+} unique_counter;
+
+/*
+** allocate new unique_data;
+** initialize, copy basedn;
+** store in on_bi.bi_private;
+**
+*/
+
+static int unique_db_init(
+	BackendDB	*be
+)
+{
+	slap_overinst *on = (slap_overinst *)be->bd_info;
+	unique_data *ud   = ch_malloc(sizeof(unique_data));
+	unique_attrs *up;
+
+	/* Debug(LDAP_DEBUG_TRACE, "==> unique_init\n", 0, 0, 0); */
+
+	ud->message	= "_init";
+	ud->attrs	= NULL;
+	ud->ignore	= NULL;
+	ud->strict	= 0;
+
+	/* default to the base of our configured database */
+	ber_dupbv(&ud->dn, &be->be_nsuffix[0]);
+	on->on_bi.bi_private = ud;
+}
+
+
+/*
+** if command = attributes:
+**	foreach argument:
+**		convert to attribute;
+**		add to configured attribute list;
+** elseif command = base:
+**	set our basedn to argument;
+** else complain about invalid directive;
+**
+*/
+
+static int unique_config(
+	BackendDB	*be,
+	const char	*fname,
+	int		lineno,
+	int		argc,
+	char		**argv
+)
+{
+	slap_overinst *on = (slap_overinst *) be->bd_info;
+	unique_data *ud	  = on->on_bi.bi_private;
+	unique_attrs *up;
+	const char *text;
+	AttributeDescription *ad;
+	int i;
+
+	ud->message = "_config";
+	Debug(LDAP_DEBUG_TRACE, "==> unique_config\n", 0, 0, 0);
+
+	if(!strcasecmp(*argv, "unique_attributes") ||
+	   !strcasecmp(*argv, "unique_ignore")) {
+		for(i = 1; i < argc; i++) {
+			for(up = ud->attrs; up; up = up->next)
+			    if(!strcmp(argv[i], up->attr->ad_cname.bv_val)) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: duplicate attribute <s>, ignored\n",
+					fname, lineno, argv[i]);
+				continue;
+			}
+			ad = NULL;
+			if(slap_str2ad(argv[i], &ad, &text) != LDAP_SUCCESS) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: bad attribute <%s>, ignored\n",
+					fname, lineno, text);
+				continue;		/* XXX */
+			} else if(ad->ad_next) {
+				Debug(LDAP_DEBUG_ANY,
+					"%s: line %d: multiple attributes match <%s>, ignored\n",
+					fname, lineno, argv[i]);
+				continue;
+			}
+			up = ch_malloc(sizeof(unique_attrs));
+			up->attr = ad;
+			if(!strcasecmp(*argv, "unique_ignore")) {
+				up->next = ud->ignore;
+				ud->ignore = up;
+			} else {
+				up->next = ud->attrs;
+				ud->attrs = up;
+			}
+			Debug(LDAP_DEBUG_ANY, "%s: line %d: new attribute <%s>\n",
+				fname, lineno, argv[i]);
+		}
+	} else if(!strcasecmp(*argv, "unique_strict")) {
+		ud->strict = 1;
+	} else if(!strcasecmp(*argv, "unique_base")) {
+		struct berval bv;
+		ber_str2bv( argv[1], 0, 0, &bv );
+		ch_free(ud->dn.bv_val);
+		dnNormalize(0, NULL, NULL, &bv, &ud->dn, NULL);
+		Debug(LDAP_DEBUG_ANY, "%s: line %d: new base dn <%s>\n",
+			fname, lineno, argv[1]);
+	} else {
+		return(SLAP_CONF_UNKNOWN);
+	}
+
+	return(0);
+}
+
+
+/*
+** mostly, just print the init message;
+**
+*/
+
+static int
+unique_open(
+	BackendDB *be
+)
+{
+	slap_overinst *on	= (slap_overinst *)be->bd_info;
+	unique_data *ud		= on->on_bi.bi_private;
+	ud->message		= "_open";
+
+	Debug(LDAP_DEBUG_TRACE, "unique_open: overlay initialized\n", 0, 0, 0);
+
+	return(0);
+}
+
+
+/*
+** foreach configured attribute:
+**	free it;
+** free our basedn;
+** (do not) free ud->message;
+** reset on_bi.bi_private;
+** free our config data;
+**
+*/
+
+static int
+unique_close(
+	BackendDB *be
+)
+{
+	slap_overinst *on	= (slap_overinst *) be->bd_info;
+	unique_data *ud		= on->on_bi.bi_private;
+	unique_attrs *ii, *ij;
+	ud->message		= "_close";
+
+	Debug(LDAP_DEBUG_TRACE, "==> unique_close\n", 0, 0, 0);
+
+	for(ii = ud->attrs; ii; ii = ij) {
+		ij = ii->next;
+		ch_free(ii);
+	}
+
+	for(ii = ud->ignore; ii; ii = ij) {
+		ij = ii->next;
+		ch_free(ii);
+	}
+
+	ch_free(ud->dn.bv_val);
+
+	on->on_bi.bi_private = NULL;	/* XXX */
+
+	ch_free(ud);
+
+	return(0);
+}
+
+
+/*
+** search callback
+**	if this is a REP_SEARCH, count++;
+**
+*/
+
+static int count_attr_cb(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	/* because you never know */
+	if(!op || !rs) return(0);
+
+	/* Only search entries are interesting */
+	if(rs->sr_type != REP_SEARCH) return(0);
+
+	Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
+		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
+
+	((unique_counter*)op->o_callback->sc_private)->count++;
+
+	return(0);
+}
+
+/* XXX extraneous (slap_response*) to avoid compiler warning */
+
+static int unique_add(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Operation nop = *op;
+	SlapReply nrs = { REP_RESULT };
+	slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
+	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+
+	Attribute *a;
+	AttributeDescription *st;
+	BerVarray b = NULL;
+	char *fstr, *key, *kp;
+	const char *why;
+	int i, rc, ks = 16;
+	unique_attrs *up;
+	unique_counter uq = { 0 };
+	unique_data *ud = on->on_bi.bi_private;
+
+	Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n", op->o_req_dn.bv_val, 0, 0);
+
+	/* validate backend. Should have already been done, but whatever */
+	nop.o_bd = select_backend(&ud->dn, 0, 1);
+	if(nop.o_bd) {
+		if (!nop.o_bd->be_search) {
+			op->o_bd->bd_info = (BackendInfo *) on->on_info;
+			send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
+			"backend missing search function");
+			return(rs->sr_err);
+		}
+	} else {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_OTHER,
+			"no known backend? this shouldn't be happening!");
+		return(rs->sr_err);
+	}
+
+/*
+** count everything first;
+** allocate some memory;
+** write the search key;
+**
+*/
+
+	if(!(a = op->ora_e->e_attrs)) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
+			"unique_add() got null op.ora_e.e_attrs");
+		return(rs->sr_err);
+	} else for(; a; a = a->a_next) {
+		if(is_at_operational(a->a_desc->ad_type)) continue;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(a->a_desc == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(a->a_desc == up->attr) break;
+			if(!up) continue;
+		}
+		if((b = a->a_vals) && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
+			ks += b[i].bv_len + a->a_desc->ad_cname.bv_len + 3;
+		else if(ud->strict)
+			ks += a->a_desc->ad_cname.bv_len + 4;	/* (attr=*) */
+	}
+
+	key = ch_malloc(ks);
+
+	kp = key + sprintf(key, "(|");
+
+	for(a = op->ora_e->e_attrs; a; a = a->a_next) {
+		if(is_at_operational(a->a_desc->ad_type)) continue;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(a->a_desc == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(a->a_desc == up->attr) break;
+			if(!up) continue;
+		}
+		if((b = a->a_vals) && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
+			kp += sprintf(kp, "(%s=%s)", a->a_desc->ad_cname.bv_val, b[i].bv_val);
+		else if(ud->strict)
+			kp += sprintf(kp, "(%s=*)", a->a_desc->ad_cname.bv_val);
+	}
+
+	kp += sprintf(kp, ")");
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_add %s\n", key, 0, 0);
+
+	nop.ors_filter = str2filter_x(&nop, key);
+	ber_str2bv(key, 0, 0, &nop.ors_filterstr);
+
+	cb.sc_response	= (slap_response*)count_attr_cb;
+	cb.sc_private	= &uq;
+	nop.o_callback	= &cb;
+	nop.o_tag	= LDAP_REQ_SEARCH;
+	nop.ors_scope	= LDAP_SCOPE_SUBTREE;
+	nop.ors_deref	= LDAP_DEREF_NEVER;
+	nop.ors_slimit	= -1;
+	nop.ors_tlimit	= -1;
+	nop.o_req_ndn	= ud->dn;
+	nop.o_ndn = op->o_bd->be_rootndn;
+
+	rc = nop.o_bd->be_search(&nop, &nrs);
+	filter_free_x(&nop, nop.ors_filter);
+	ch_free( key );
+
+	if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, rc, "unique_add search failed");
+		return(rs->sr_err);
+	}
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_add found %d records\n", uq.count, 0, 0);
+
+	if(uq.count) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
+			"some attributes not unique");
+		return(rs->sr_err);
+	}
+
+	return(SLAP_CB_CONTINUE);
+}
+
+
+static int unique_modify(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Operation nop = *op;
+	SlapReply nrs = { REP_RESULT };
+	slap_callback cb = { NULL, (slap_response*)count_attr_cb, NULL, NULL };
+	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+
+	Attribute *a;
+	AttributeDescription *st;
+	BerVarray b = NULL;
+	Modifications *m;
+	char *fstr, *key, *kp;
+	const char *why;
+	int i, rc, ks = 16;		/* a handful of extra bytes */
+	unique_attrs *up;
+	unique_counter uq = { 0 };
+	unique_data *ud = on->on_bi.bi_private;
+
+	Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n", op->o_req_dn.bv_val, 0, 0);
+
+	nop.o_bd = select_backend(&ud->dn, 0, 1);
+	if(nop.o_bd) {
+		if (!nop.o_bd->be_search) {
+			op->o_bd->bd_info = (BackendInfo *) on->on_info;
+			send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
+			"backend missing search function");
+			return(rs->sr_err);
+		}
+	} else {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_OTHER,
+			"no known backend? this shouldn't be happening!");
+		return(rs->sr_err);
+	}
+
+/*
+** count everything first;
+** allocate some memory;
+** write the search key;
+**
+*/
+
+	if(!(m = op->orm_modlist)) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
+			"unique_modify() got null op.orm_modlist");
+		return(rs->sr_err);
+	} else for(; m; m = m->sml_next) {
+		if(is_at_operational(m->sml_desc->ad_type) ||
+			((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE)) continue;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(m->sml_desc == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(m->sml_desc == up->attr) break;
+			if(!up) continue;
+		}
+		if((b = m->sml_values) && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
+			ks += b[i].bv_len + m->sml_desc->ad_cname.bv_len + 3;
+		else if(ud->strict)
+			ks += m->sml_desc->ad_cname.bv_len + 4;	/* (attr=*) */
+	}
+
+	key = ch_malloc(ks);
+
+	kp = key + sprintf(key, "(|");
+
+	for(m = op->orm_modlist; m; m = m->sml_next) {
+		if(is_at_operational(m->sml_desc->ad_type) ||
+			((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE)) continue;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(m->sml_desc == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(m->sml_desc == up->attr) break;
+			if(!up) continue;
+		}
+		if((b = m->sml_values) && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
+			kp += sprintf(kp, "(%s=%s)", m->sml_desc->ad_cname.bv_val, b[i].bv_val);
+		else if(ud->strict)
+			kp += sprintf(kp, "(%s=*)", m->sml_desc->ad_cname.bv_val);
+	}
+
+	kp += sprintf(kp, ")");
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_modify %s\n", key, 0, 0);
+
+	nop.ors_filter = str2filter_x(&nop, key);
+	ber_str2bv(key, 0, 0, &nop.ors_filterstr);
+
+	cb.sc_response	= (slap_response*)count_attr_cb;
+	cb.sc_private	= &uq;
+	nop.o_callback	= &cb;
+	nop.o_tag	= LDAP_REQ_SEARCH;
+	nop.ors_scope	= LDAP_SCOPE_SUBTREE;
+	nop.ors_deref	= LDAP_DEREF_NEVER;
+	nop.ors_slimit	= -1;
+	nop.ors_tlimit	= -1;
+	nop.o_req_ndn	= ud->dn;
+	nop.o_ndn = op->o_bd->be_rootndn;
+
+	rc = nop.o_bd->be_search(&nop, &nrs);
+	ch_free( key );
+
+	if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, rc, "unique_modify search failed");
+		return(rs->sr_err);
+	}
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_modify found %d records\n", uq.count, 0, 0);
+
+	if(uq.count) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
+			"some attributes not unique");
+		return(rs->sr_err);
+	}
+
+	return(SLAP_CB_CONTINUE);
+
+}
+
+
+static int unique_modrdn(
+	Operation *op,
+	SlapReply *rs
+)
+{
+	Operation nop = *op;
+	SlapReply nrs = { REP_RESULT };
+	slap_callback cb = { NULL, (slap_response*)count_attr_cb, NULL, NULL };
+	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+
+	char *fstr, *key, *kp;
+	const char *why;
+	int i, rc, ks = 16;		/* a handful of extra bytes */
+	unique_attrs *up;
+	unique_counter uq = { 0 };
+	unique_data *ud = on->on_bi.bi_private;
+	LDAPRDN	newrdn;
+
+	Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
+		op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
+
+	nop.o_bd = select_backend(&ud->dn, 0, 1);
+	if(nop.o_bd) {
+		if (!nop.o_bd->be_search) {
+			op->o_bd->bd_info = (BackendInfo *) on->on_info;
+			send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
+			"backend missing search function");
+			return(rs->sr_err);
+		}
+	} else {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_OTHER,
+			"no known backend? this shouldn't be happening!");
+		return(rs->sr_err);
+	}
+
+	if(ldap_bv2rdn_x(&op->oq_modrdn.rs_newrdn, &newrdn,
+		(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx )) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
+			"unknown type(s) used in RDN");
+		return(rs->sr_err);
+	}
+	for(i = 0; newrdn[i]; i++) {
+		AttributeDescription *ad = NULL;
+		if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
+			ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
+			rs->sr_err = LDAP_INVALID_SYNTAX;
+			send_ldap_result( op, rs );
+			return(rs->sr_err);
+		}
+		newrdn[i]->la_private = ad;
+	}
+
+	for(i = 0; newrdn[i]; i++) {
+		AttributeDescription *ad = newrdn[i]->la_private;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(ad == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(ad == up->attr) break;
+			if(!up) continue;
+		}
+		ks += newrdn[i]->la_value.bv_len + ad->ad_cname.bv_len + 3;
+	}
+
+	key = ch_malloc(ks);
+	kp = key + sprintf(key, "(|");
+
+	for(i = 0; newrdn[i]; i++) {
+		AttributeDescription *ad = newrdn[i]->la_private;
+		if(ud->ignore) {
+			for(up = ud->ignore; up; up = up->next)
+				if(ad == up->attr) break;
+			if(up) continue;
+		}
+		if(ud->attrs) {
+			for(up = ud->attrs; up; up = up->next)
+				if(ad == up->attr) break;
+			if(!up) continue;
+		}
+		kp += sprintf(kp, "(%s=%s)", ad->ad_cname.bv_val,
+			newrdn[i]->la_value.bv_val);
+	}
+
+	kp += sprintf(kp, ")");
+
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_modrdn %s\n", key, 0, 0);
+
+	nop.ors_filter = str2filter_x(&nop, key);
+	ber_str2bv(key, 0, 0, &nop.ors_filterstr);
+
+	cb.sc_response	= (slap_response*)count_attr_cb;
+	cb.sc_private	= &uq;
+	nop.o_callback	= &cb;
+	nop.o_tag	= LDAP_REQ_SEARCH;
+	nop.ors_scope	= LDAP_SCOPE_SUBTREE;
+	nop.ors_deref	= LDAP_DEREF_NEVER;
+	nop.ors_slimit	= -1;
+	nop.ors_tlimit	= -1;
+	nop.o_req_ndn	= ud->dn;
+	nop.o_ndn = op->o_bd->be_rootndn;
+
+	rc = nop.o_bd->be_search(&nop, &nrs);
+	ch_free( key );
+	ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
+
+	if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, rc, "unique_modrdn search failed");
+		return(rs->sr_err);
+	}
+
+	Debug(LDAP_DEBUG_TRACE, "=> unique_modrdn found %d records\n", uq.count, 0, 0);
+
+	if(uq.count) {
+		op->o_bd->bd_info = (BackendInfo *) on->on_info;
+		send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
+			"some attributes not unique");
+		return(rs->sr_err);
+	}
+
+	return(SLAP_CB_CONTINUE);
+}
+
+/*
+** init_module is last so the symbols resolve "for free" --
+** it expects to be called automagically during dynamic module initialization
+*/
+
+int unique_init() {
+
+	/* statically declared just after the #includes at top */
+	unique.on_bi.bi_type = "unique";
+	unique.on_bi.bi_db_init = unique_db_init;
+	unique.on_bi.bi_db_config = unique_config;
+	unique.on_bi.bi_db_open = unique_open;
+	unique.on_bi.bi_db_close = unique_close;
+	unique.on_bi.bi_op_add = unique_add;
+	unique.on_bi.bi_op_modify = unique_modify;
+	unique.on_bi.bi_op_modrdn = unique_modrdn;
+	unique.on_bi.bi_op_delete = NULL;
+
+	return(overlay_register(&unique));
+}
+
+#if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
+int init_module(int argc, char *argv[]) {
+	return unique_init();
+}
+#endif
+
+#endif /* SLAPD_OVER_UNIQUE */