From cfaf57e291ac41ed36669034ab4033e94dab3ef0 Mon Sep 17 00:00:00 2001
From: William Brown <firstyear@redhat.com>
Date: Tue, 7 Jun 2016 13:54:52 +1000
Subject: [PATCH] Ticket 48272 - ADDN Style prebind plugin

Fix Description:  This plugin allows a unique entry that matches some filter
to bind with "user1" -> "uid=user1,ou=People,dc=example,dc=com" or the AD syntax
"user1@example.com" -> "uid=user1,ou=People,dc=example,dc=com"

For the user to bind:

* Only a single entry may be mapped from the filter, else it is considered a failure.
* The entry must belong under a specific suffix
* If user@domain.com, domain.com -> dc=domain,dc=com is the search base.

https://fedorahosted.org/389/ticket/48272

Author: wibrown

Review by: ???
---
 Makefile.am                                   |  14 +-
 Makefile.in                                   |  54 +++-
 dirsrvtests/tests/tickets/ticket48272_test.py | 175 +++++++++++
 ldap/servers/plugins/addn/addn.c              | 420 ++++++++++++++++++++++++++
 ldap/servers/plugins/addn/addn.h              |  22 ++
 ldap/servers/slapd/bind.c                     |   5 +
 ldap/servers/slapd/plugin.c                   |  13 +-
 7 files changed, 695 insertions(+), 8 deletions(-)
 create mode 100644 dirsrvtests/tests/tickets/ticket48272_test.py
 create mode 100644 ldap/servers/plugins/addn/addn.c
 create mode 100644 ldap/servers/plugins/addn/addn.h

diff --git a/Makefile.am b/Makefile.am
index 0341909..b6ebf92 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -249,7 +249,9 @@ LIBACCTPOLICY_SCHEMA = $(srcdir)/ldap/schema/60acctpolicy.ldif
 enable_acctpolicy = 1
 endif
 
-serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
+serverplugin_LTLIBRARIES = libacl-plugin.la \
+	libaddn-plugin.la \
+	libattr-unique-plugin.la \
 	libautomember-plugin.la libback-ldbm.la libchainingdb-plugin.la \
 	libcollation-plugin.la libcos-plugin.la libderef-plugin.la \
 	libpbe-plugin.la libdistrib-plugin.la libhttp-client-plugin.la \
@@ -330,6 +332,7 @@ dist_noinst_HEADERS = \
 	ldap/include/regex.h \
 	ldap/include/srchpref.h \
 	ldap/include/sysexits-compat.h \
+	ldap/servers/plugins/addn/addn.h \
 	ldap/servers/plugins/collation/config.h \
 	ldap/servers/plugins/collation/collate.h \
 	ldap/servers/plugins/collation/orfilter.h \
@@ -1177,6 +1180,15 @@ libacl_plugin_la_LDFLAGS = -avoid-version
 libacl_plugin_la_LINK = $(CXXLINK) -avoid-version
 
 #------------------------
+# libaddn-plugin
+#------------------------
+libaddn_plugin_la_SOURCES = ldap/servers/plugins/addn/addn.c
+
+libaddn_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+libaddn_plugin_la_LIBADD = libslapd.la $(NSPR_LINK)
+libaddn_plugin_la_LDFLAGS = -avoid-version
+
+#------------------------
 # librootdn-access-plugin
 #------------------------
 #
diff --git a/Makefile.in b/Makefile.in
index b75dc58..3305811 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -233,6 +233,14 @@ am_libacl_plugin_la_OBJECTS =  \
 	ldap/servers/plugins/acl/libacl_plugin_la-aclplugin.lo \
 	ldap/servers/plugins/acl/libacl_plugin_la-aclutil.lo
 libacl_plugin_la_OBJECTS = $(am_libacl_plugin_la_OBJECTS)
+libaddn_plugin_la_DEPENDENCIES = libslapd.la $(am__DEPENDENCIES_1)
+am_libaddn_plugin_la_OBJECTS =  \
+	ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo
+libaddn_plugin_la_OBJECTS = $(am_libaddn_plugin_la_OBJECTS)
+libaddn_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(libaddn_plugin_la_LDFLAGS) $(LDFLAGS) \
+	-o $@
 libattr_unique_plugin_la_DEPENDENCIES = libslapd.la \
 	$(am__DEPENDENCIES_1)
 am_libattr_unique_plugin_la_OBJECTS =  \
@@ -1157,7 +1165,7 @@ am__v_CXXLD_1 =
 SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libacctpolicy_plugin_la_SOURCES) \
 	$(libacctusability_plugin_la_SOURCES) \
-	$(libacl_plugin_la_SOURCES) \
+	$(libacl_plugin_la_SOURCES) $(libaddn_plugin_la_SOURCES) \
 	$(libattr_unique_plugin_la_SOURCES) \
 	$(libautomember_plugin_la_SOURCES) $(libback_ldbm_la_SOURCES) \
 	$(libbitwise_plugin_la_SOURCES) \
@@ -1192,7 +1200,7 @@ SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 DIST_SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libacctpolicy_plugin_la_SOURCES) \
 	$(libacctusability_plugin_la_SOURCES) \
-	$(libacl_plugin_la_SOURCES) \
+	$(libacl_plugin_la_SOURCES) $(libaddn_plugin_la_SOURCES) \
 	$(libattr_unique_plugin_la_SOURCES) \
 	$(libautomember_plugin_la_SOURCES) $(libback_ldbm_la_SOURCES) \
 	$(libbitwise_plugin_la_SOURCES) \
@@ -1671,7 +1679,9 @@ server_LTLIBRARIES = libslapd.la libns-dshttpd.la
 @enable_acctpolicy_TRUE@LIBACCTPOLICY_PLUGIN = libacctpolicy-plugin.la
 @enable_acctpolicy_TRUE@LIBACCTPOLICY_SCHEMA = $(srcdir)/ldap/schema/60acctpolicy.ldif
 @enable_acctpolicy_TRUE@enable_acctpolicy = 1
-serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
+serverplugin_LTLIBRARIES = libacl-plugin.la \
+	libaddn-plugin.la \
+	libattr-unique-plugin.la \
 	libautomember-plugin.la libback-ldbm.la libchainingdb-plugin.la \
 	libcollation-plugin.la libcos-plugin.la libderef-plugin.la \
 	libpbe-plugin.la libdistrib-plugin.la libhttp-client-plugin.la \
@@ -1748,6 +1758,7 @@ dist_noinst_HEADERS = \
 	ldap/include/regex.h \
 	ldap/include/srchpref.h \
 	ldap/include/sysexits-compat.h \
+	ldap/servers/plugins/addn/addn.h \
 	ldap/servers/plugins/collation/config.h \
 	ldap/servers/plugins/collation/collate.h \
 	ldap/servers/plugins/collation/orfilter.h \
@@ -2536,6 +2547,14 @@ libacl_plugin_la_LDFLAGS = -avoid-version
 libacl_plugin_la_LINK = $(CXXLINK) -avoid-version
 
 #------------------------
+# libaddn-plugin
+#------------------------
+libaddn_plugin_la_SOURCES = ldap/servers/plugins/addn/addn.c
+libaddn_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+libaddn_plugin_la_LIBADD = libslapd.la $(NSPR_LINK)
+libaddn_plugin_la_LDFLAGS = -avoid-version
+
+#------------------------
 # librootdn-access-plugin
 #------------------------
 #
@@ -3494,6 +3513,18 @@ ldap/servers/plugins/acl/libacl_plugin_la-aclutil.lo:  \
 
 libacl-plugin.la: $(libacl_plugin_la_OBJECTS) $(libacl_plugin_la_DEPENDENCIES) $(EXTRA_libacl_plugin_la_DEPENDENCIES) 
 	$(AM_V_GEN)$(libacl_plugin_la_LINK) -rpath $(serverplugindir) $(libacl_plugin_la_OBJECTS) $(libacl_plugin_la_LIBADD) $(LIBS)
+ldap/servers/plugins/addn/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/addn
+	@: > ldap/servers/plugins/addn/$(am__dirstamp)
+ldap/servers/plugins/addn/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/addn/$(DEPDIR)
+	@: > ldap/servers/plugins/addn/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo:  \
+	ldap/servers/plugins/addn/$(am__dirstamp) \
+	ldap/servers/plugins/addn/$(DEPDIR)/$(am__dirstamp)
+
+libaddn-plugin.la: $(libaddn_plugin_la_OBJECTS) $(libaddn_plugin_la_DEPENDENCIES) $(EXTRA_libaddn_plugin_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libaddn_plugin_la_LINK) -rpath $(serverplugindir) $(libaddn_plugin_la_OBJECTS) $(libaddn_plugin_la_LIBADD) $(LIBS)
 ldap/servers/plugins/uiduniq/$(am__dirstamp):
 	@$(MKDIR_P) ldap/servers/plugins/uiduniq
 	@: > ldap/servers/plugins/uiduniq/$(am__dirstamp)
@@ -5487,6 +5518,8 @@ mostlyclean-compile:
 	-rm -f ldap/servers/plugins/acctpolicy/*.lo
 	-rm -f ldap/servers/plugins/acl/*.$(OBJEXT)
 	-rm -f ldap/servers/plugins/acl/*.lo
+	-rm -f ldap/servers/plugins/addn/*.$(OBJEXT)
+	-rm -f ldap/servers/plugins/addn/*.lo
 	-rm -f ldap/servers/plugins/automember/*.$(OBJEXT)
 	-rm -f ldap/servers/plugins/automember/*.lo
 	-rm -f ldap/servers/plugins/bitwise/*.$(OBJEXT)
@@ -5590,6 +5623,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/acl/$(DEPDIR)/libacl_plugin_la-aclparse.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/acl/$(DEPDIR)/libacl_plugin_la-aclplugin.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/acl/$(DEPDIR)/libacl_plugin_la-aclutil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/addn/$(DEPDIR)/libaddn_plugin_la-addn.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/automember/$(DEPDIR)/libautomember_plugin_la-automember.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/bitwise/$(DEPDIR)/libbitwise_plugin_la-bitwise.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/chainingdb/$(DEPDIR)/libchainingdb_plugin_la-cb_abandon.Plo@am__quote@
@@ -6318,6 +6352,13 @@ ldap/servers/plugins/acl/libacl_plugin_la-aclutil.lo: ldap/servers/plugins/acl/a
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libacl_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/acl/libacl_plugin_la-aclutil.lo `test -f 'ldap/servers/plugins/acl/aclutil.c' || echo '$(srcdir)/'`ldap/servers/plugins/acl/aclutil.c
 
+ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo: ldap/servers/plugins/addn/addn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libaddn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo -MD -MP -MF ldap/servers/plugins/addn/$(DEPDIR)/libaddn_plugin_la-addn.Tpo -c -o ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo `test -f 'ldap/servers/plugins/addn/addn.c' || echo '$(srcdir)/'`ldap/servers/plugins/addn/addn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ldap/servers/plugins/addn/$(DEPDIR)/libaddn_plugin_la-addn.Tpo ldap/servers/plugins/addn/$(DEPDIR)/libaddn_plugin_la-addn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ldap/servers/plugins/addn/addn.c' object='ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libaddn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/addn/libaddn_plugin_la-addn.lo `test -f 'ldap/servers/plugins/addn/addn.c' || echo '$(srcdir)/'`ldap/servers/plugins/addn/addn.c
+
 ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-7bit.lo: ldap/servers/plugins/uiduniq/7bit.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libattr_unique_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-7bit.lo -MD -MP -MF ldap/servers/plugins/uiduniq/$(DEPDIR)/libattr_unique_plugin_la-7bit.Tpo -c -o ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-7bit.lo `test -f 'ldap/servers/plugins/uiduniq/7bit.c' || echo '$(srcdir)/'`ldap/servers/plugins/uiduniq/7bit.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ldap/servers/plugins/uiduniq/$(DEPDIR)/libattr_unique_plugin_la-7bit.Tpo ldap/servers/plugins/uiduniq/$(DEPDIR)/libattr_unique_plugin_la-7bit.Plo
@@ -9844,6 +9885,7 @@ clean-libtool:
 	-rm -rf ldap/servers/plugins/acct_usability/.libs ldap/servers/plugins/acct_usability/_libs
 	-rm -rf ldap/servers/plugins/acctpolicy/.libs ldap/servers/plugins/acctpolicy/_libs
 	-rm -rf ldap/servers/plugins/acl/.libs ldap/servers/plugins/acl/_libs
+	-rm -rf ldap/servers/plugins/addn/.libs ldap/servers/plugins/addn/_libs
 	-rm -rf ldap/servers/plugins/automember/.libs ldap/servers/plugins/automember/_libs
 	-rm -rf ldap/servers/plugins/bitwise/.libs ldap/servers/plugins/bitwise/_libs
 	-rm -rf ldap/servers/plugins/chainingdb/.libs ldap/servers/plugins/chainingdb/_libs
@@ -10532,6 +10574,8 @@ distclean-generic:
 	-rm -f ldap/servers/plugins/acctpolicy/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/acl/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/acl/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/addn/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/addn/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/automember/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/automember/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/bitwise/$(DEPDIR)/$(am__dirstamp)
@@ -10632,7 +10676,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acct_usability/$(DEPDIR) ldap/servers/plugins/acctpolicy/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/automember/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/deref/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/mep/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/posix-winsync/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/rootdn_access/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/sync/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/plugins/whoami/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
+	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acct_usability/$(DEPDIR) ldap/servers/plugins/acctpolicy/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/addn/$(DEPDIR) ldap/servers/plugins/automember/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/deref/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/mep/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/posix-winsync/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/rootdn_access/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/sync/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/plugins/whoami/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags
@@ -10688,7 +10732,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acct_usability/$(DEPDIR) ldap/servers/plugins/acctpolicy/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/automember/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/deref/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/mep/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/posix-winsync/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/rootdn_access/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/sync/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/plugins/whoami/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
+	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acct_usability/$(DEPDIR) ldap/servers/plugins/acctpolicy/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/addn/$(DEPDIR) ldap/servers/plugins/automember/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/deref/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/mep/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/posix-winsync/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/rootdn_access/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/sync/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/plugins/whoami/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/dirsrvtests/tests/tickets/ticket48272_test.py b/dirsrvtests/tests/tickets/ticket48272_test.py
new file mode 100644
index 0000000..6686a9a
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket48272_test.py
@@ -0,0 +1,175 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+
+DEBUGGING = True
+
+if DEBUGGING:
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+    logging.getLogger(__name__).setLevel(logging.INFO)
+
+
+log = logging.getLogger(__name__)
+
+USER1 = 'user1'
+USER1_DOMAIN = 'user1@example.com'
+PW = 'password'
+USER1_DN = 'uid=user1,ou=People,%s' % DEFAULT_SUFFIX
+USER1_CONFLICT_DN = 'uid=user1,%s' % DEFAULT_SUFFIX
+
+
+class TopologyStandalone(object):
+    """The DS Topology Class"""
+    def __init__(self, standalone):
+        """Init"""
+        standalone.open()
+        self.standalone = standalone
+
+
+@pytest.fixture(scope="module")
+def topology(request):
+    """Create DS Deployment"""
+
+    # Creating standalone instance ...
+    if DEBUGGING:
+        standalone = DirSrv(verbose=True)
+    else:
+        standalone = DirSrv(verbose=False)
+    args_instance[SER_HOST] = HOST_STANDALONE
+    args_instance[SER_PORT] = PORT_STANDALONE
+    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
+    args_standalone = args_instance.copy()
+    standalone.allocate(args_standalone)
+    instance_standalone = standalone.exists()
+    if instance_standalone:
+        standalone.delete()
+    standalone.create()
+    standalone.open()
+
+    def fin():
+        """If we are debugging just stop the instances, otherwise remove
+        them
+        """
+        if DEBUGGING:
+            standalone.stop(60)
+        else:
+            standalone.delete()
+
+    request.addfinalizer(fin)
+
+    # Clear out the tmp dir
+    standalone.clearTmpDir(__file__)
+
+    return TopologyStandalone(standalone)
+
+def _create_user(inst, name, dn):
+    inst.add_s(Entry((
+                dn, {
+                    'objectClass': 'top account simplesecurityobject'.split(),
+                     'uid': name,
+                     'userpassword': PW
+                })))
+
+def _bind(name, cred):
+    # Returns true or false if it worked.
+    if DEBUGGING:
+        print('test 48272 BINDING AS %s:%s' % (name, cred))
+    status = True
+    conn = ldap.initialize("ldap://%s:%s" % (HOST_STANDALONE, PORT_STANDALONE))
+    try:
+        conn.simple_bind_s(name, cred)
+        conn.unbind_s()
+    except ldap.NO_SUCH_OBJECT:
+        status = False
+    return status
+
+
+def test_ticket48272(topology):
+    """
+    Test the functionality of the ADDN bind plugin. This should allow users
+    of the type "name" or "name@domain.com" to bind.
+    """
+
+    # Enable the plugin
+
+    # There will be a better way to do this in the future.
+    topology.standalone.add_s(Entry((
+        "cn=ADDN,cn=plugins,cn=config", {
+            "objectClass" : "top nsSlapdPlugin extensibleObject".split(),
+            "cn" : "ADDN",
+            "nsslapd-pluginPath": "libaddn-plugin",
+            "nsslapd-pluginInitfunc": "addn_init",
+            "nsslapd-pluginType": "preoperation",
+            "nsslapd-pluginEnabled": "on",
+            "nsslapd-pluginId": "addn",
+            "nsslapd-pluginVendor": "389 Project",
+            "nsslapd-pluginVersion": "1.3.4.0",
+            "nsslapd-pluginDescription": "Allow AD DN style bind names to LDAP",
+            "addn_default_suffix": "ou=People,%s" % DEFAULT_SUFFIX,
+            "addn_filter": "(&(objectClass=account)(uid=%s))",
+        }
+    )))
+
+    topology.standalone.restart(60)
+
+    # Add a user
+    _create_user(topology.standalone, USER1, USER1_DN)
+
+    # Make sure our binds still work.
+    assert(_bind(USER1_DN, PW))
+    # Test an anonymous bind
+    for i in range(0,10):
+
+        # Test bind as name
+        assert(_bind(USER1, PW))
+
+        # Make sure that name@fakedom fails
+        # WARNING: This will change in the future!!!!
+        assert(_bind(USER1_DOMAIN, PW))
+
+    # Add a conflicting user to an alternate subtree
+    _create_user(topology.standalone, USER1, USER1_CONFLICT_DN)
+    # Change the plugin to search from the rootdn instead
+    # This means we have a conflicting user in scope now!
+
+    topology.standalone.modify_s("cn=ADDN,cn=plugins,cn=config", [(ldap.MOD_REPLACE, 'addn_default_suffix', DEFAULT_SUFFIX)])
+    topology.standalone.restart(60)
+
+    # Make sure our binds still work.
+    assert(_bind(USER1_DN, PW))
+    assert(_bind(USER1_CONFLICT_DN, PW))
+    for i in range(0,10):
+
+        # Test bind as name fails
+        try:
+            _bind(USER1, PW)
+            assert(False)
+        except:
+            pass
+        # Test bind as name@domain fails too
+        try:
+            _bind(USER1_DOMAIN, PW)
+            assert(False)
+        except:
+            pass
+
+    log.info('Test PASSED')
+
+
+if __name__ == '__main__':
+    # Run isolated
+    # -s for DEBUG mode
+    CURRENT_FILE = os.path.realpath(__file__)
+    pytest.main("-s %s" % CURRENT_FILE)
+
diff --git a/ldap/servers/plugins/addn/addn.c b/ldap/servers/plugins/addn/addn.c
new file mode 100644
index 0000000..19f56ab
--- /dev/null
+++ b/ldap/servers/plugins/addn/addn.c
@@ -0,0 +1,420 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright (C) 2016 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * License: GPL (version 3 or any later version).
+ * See LICENSE for details. 
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/*
+ * AD DN bind plugin
+ *
+ * This plugin allows violation of the LDAP v3 standard for binds to occur
+ * as "uid" or "uid@example.com". This plugin re-maps those terms to a real
+ * dn such as uid=user,ou=People,dc=example,dc=com.
+ */
+
+#include "addn.h"
+
+/* is there a better type we can use here? */
+#define ADDN_FAILURE 1
+#define SLAPI_LOG_PLUGIN 0
+
+static void* plugin_identity = NULL;
+
+static Slapi_PluginDesc addn_description = {
+    "addn",
+    VENDOR,
+    DS_PACKAGE_VERSION,
+    "Allow AD DN style bind names to LDAP"
+};
+
+int
+addn_filter_validate(char *config_filter)
+{
+    /* Copy the filter */
+    size_t slen = strlen(config_filter);
+    int found = 0;
+    int percent_last = 0;
+
+    for (size_t i = 0; i < slen; i++) {
+        if (percent_last == 1 && config_filter[i] == 's') {
+            found += 1;
+            percent_last = 0;
+        } else if (percent_last == 0 && config_filter[i] == '%') {
+            percent_last = 1;
+        } else {
+            percent_last = 0;
+        }
+    }
+
+    if (found == 1) {
+        return LDAP_SUCCESS;
+    }
+
+    /* Is there a way to now compile and check the filter syntax? */
+
+    return 1;
+}
+
+int
+addn_prebind(Slapi_PBlock *pb)
+{
+    // Slapi_Entry *plugin_entry = NULL;
+    struct addn_config *config = NULL;
+    Slapi_DN *pb_sdn_target = NULL;
+    Slapi_DN *pb_sdn_mapped = NULL;
+    const char *dn = NULL;
+
+    const char *dn_bind = NULL;
+    int dn_bind_len = 0;
+    char *dn_bind_escaped = NULL;
+
+    const char *dn_domain = NULL;
+    int dn_domain_len = 0;
+    char *dn_domain_escaped = NULL;
+
+    char *be_suffix = NULL;
+    Slapi_DN *be_suffix_dn = NULL;
+    char *config_filter = NULL;
+    char *filter = NULL;
+    int result = 0;
+
+    Slapi_PBlock *search_pblock = NULL;
+    int search_result = 0;
+    Slapi_Entry **entries = NULL;
+    int entry_count = 0;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "--> begin\n");
+    /* This is taking .2 of a second on my laptop .... */
+    /* Perhaps it's because I'm using -O0? */
+    slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &pb_sdn_target);
+    dn = slapi_sdn_get_dn(pb_sdn_target);
+    if (dn == NULL) {
+        result = ADDN_FAILURE;
+        goto out;
+    }
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Recieved %s\n", dn);
+
+    result = slapi_dn_syntax_check(NULL, dn, 0);
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Dn validation %d\n", result);
+
+    if (result == LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Dn syntax is correct, do not alter\n");
+        /* This is a syntax correct bind dn. Leave it alone! */
+        goto out;
+    }
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Dn syntax is incorrect, it may need ADDN mangaling\n");
+
+
+    result = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
+    if (result != LDAP_SUCCESS || config == NULL) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Unable to retrieve plugin configuration!\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    /* Right, the dn is invalid! This means it *could* be addn syntax */
+    /* Do we have any other validation to run here? */
+    /* Split the @domain component (if any) */
+
+    dn_bind = strtok(dn, "@");
+
+    /* Filter escape the name, and the domain parts */
+    if (dn_bind != NULL) {
+        dn_bind_len = strlen(dn_bind);
+        dn_bind_escaped = slapi_escape_filter_value(dn_bind, dn_bind_len);
+        dn_bind_len = strlen(dn_bind_escaped);
+    }
+
+    dn_domain = strtok(NULL, "@");
+
+    /* The handling of user@domain isn't done yet: This code is a placeholder */
+    if (dn_domain != NULL) {
+        dn_domain_len = strlen(dn_domain);
+        dn_domain_escaped = slapi_escape_filter_value(dn_domain, dn_domain_len);
+        dn_domain_len = strlen(dn_domain_escaped);
+    }
+
+    /* If we don't have the @domain. get a default from config */
+
+    if (dn_domain_escaped == NULL) {
+        /* This could alternately be domain, then we do the same domain -> suffix conversion .... */
+        if (config->default_suffix == NULL) {
+            slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: No default backend in configuration, you must set addn_default_suffix\n");
+            result = ADDN_FAILURE;
+            goto out;
+        }
+        /* Select the correct backend. If no backend, bail. */
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Selected suffix %s\n", config->default_suffix);
+        be_suffix_dn = slapi_sdn_new_dn_byval(config->default_suffix);
+    } else {
+        /* Future: Parse the domain out to a potential suffix name. */
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "dn_domain_escaped %s\n", dn_domain_escaped);
+        /* I think for now, we assume that a.b.c => dc=a,dc=b,dc=c */
+        size_t be_suffix_len = 1;
+        size_t offset = 0;
+        be_suffix = slapi_ch_malloc(sizeof(char) * be_suffix_len);
+        char *token = strtok(dn_domain_escaped, ".");
+        while (token != NULL) {
+            /* check len of the token. */
+            size_t len = strlen(token);
+            /* Expand be_suffix by len + 4 (,dc=) */
+            be_suffix_len = be_suffix_len + len + 4;
+            be_suffix = slapi_ch_realloc(be_suffix, be_suffix_len);
+            /* Inject our content at the start. */
+            strncpy(be_suffix + offset, ",dc=", 4);
+            strncpy(be_suffix + offset + 4, token, len);
+            /* bump the offset */
+            offset = offset + len + 4;
+            be_suffix[offset] = '\0';
+            token = strtok(NULL, ".");
+        }
+        /* Force the last char to be null. */
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Domain %s to suffix %s\n", dn_domain_escaped, be_suffix + 1);
+        /* Start at +1 to trim the leading , off. */
+        be_suffix_dn = slapi_sdn_new_dn_byval(be_suffix + 1);
+        slapi_ch_free_string(&be_suffix);
+    }
+
+    /* Get our filter. From the config */
+    config_filter = config->filter_template;
+
+    /* Put the search term into the filter. */
+    //!! How does this return errors, like not enough values? Too many?
+    //!! This needs a careful check and review!!!
+    filter = slapi_ch_smprintf(config_filter, dn_bind_escaped);
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "Searching with filter %s\n", filter);
+
+    /* Search the backend, and apply our filter given the username */
+    search_pblock = slapi_pblock_new();
+
+    if (search_pblock == NULL) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Unable to allocate search_pblock!!!\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    // How can I do this search to retrieve NO attributes, only the DN?
+
+    slapi_search_internal_set_pb_ext(search_pblock, be_suffix_dn, LDAP_SCOPE_SUBTREE,
+                                     filter, NULL, 0 /* attrs only */,
+                                     NULL /* controls */, NULL /* uniqueid */, 
+                                     plugin_identity, 0 /* actions */);
+    slapi_search_internal_pb(search_pblock);
+
+    result = slapi_pblock_get(search_pblock, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+    if (result != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Internal search pblock get failed!!!\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    /* No results are an error: Allow the plugin to continue, because */
+    /* the bind will fail anyway ....? */
+
+    /* Do we want to return a fail here? Or pass, and allow the auth code
+     * to fail us. That will prevent some attacks I feel as this could be a
+     * disclosure attack ....
+     */
+    if (search_result == LDAP_NO_SUCH_OBJECT) {
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "LDAP_NO_SUCH_OBJECT \n");
+        result = LDAP_SUCCESS;
+        goto out;
+    }
+
+    /* On all other errors, just fail out. */
+    if (search_result != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "CRITICAL: Internal search error occured %d \n", search_result);
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+
+    result = slapi_pblock_get(search_pblock, SLAPI_NENTRIES, &entry_count);
+
+    if (result != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Unable to retrieve number of entries from pblock!\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+    /* If there are multiple results, we should also fail as we cannot */
+    /* be sure of the real object we want to bind to */
+
+    if (entry_count > 1) {
+        /*  Is there a better log level for this? */
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "WARNING, multiple results returned. Failing to auth ...\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    result = slapi_pblock_get(search_pblock, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+    if (result != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Unable to retrieve entries from pblock!\n");
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    /* We should only have one entry here! */
+
+    pb_sdn_mapped = slapi_sdn_dup(slapi_entry_get_sdn(*entries));
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "SEARCH entry dn=%s is mapped from addn=%s\n", slapi_sdn_get_dn(pb_sdn_mapped), dn);
+
+
+    /* If there is a result, take the DN and make the SDN for PB */
+
+    /* Free the original SDN */
+    result = slapi_pblock_set(pb, SLAPI_TARGET_SDN, pb_sdn_mapped);
+    if (result != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_prebind", "CRITICAL: Unable to set new mapped DN to pblock!\n");
+        /* We have to free the mapped SDN here */
+        slapi_sdn_free(&pb_sdn_mapped);
+        result = ADDN_FAILURE;
+        goto out;
+    }
+
+    slapi_sdn_free(&pb_sdn_target);
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_prebind", "<-- complete\n");
+
+    result = LDAP_SUCCESS;
+
+out:
+    if (search_pblock != NULL) {
+        slapi_free_search_results_internal(search_pblock);
+        slapi_pblock_destroy(search_pblock);
+    }
+    slapi_sdn_free(&be_suffix_dn);
+    slapi_ch_free_string(&dn_bind_escaped);
+    slapi_ch_free_string(&dn_domain_escaped);
+    slapi_ch_free_string(&filter);
+
+    return result;
+}
+
+
+/*
+ * addn_start
+ *
+ * This is called when the plugin is started. It allows a configuration change
+ * To be made while the directory server is live.
+ */
+int
+addn_start(Slapi_PBlock *pb)
+{
+    Slapi_Entry *plugin_entry = NULL;
+    struct addn_config *config = NULL;
+    int result = LDAP_SUCCESS;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_start", "starting ...\n");
+
+    /* I have no idea how this works .... should be SLAPI_PLUGIN_CONFIG */
+    result = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &plugin_entry);
+    if (result != LDAP_SUCCESS || plugin_entry == NULL) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_start", "CRITICAL: Failed to retrieve config entry!\n");
+        return SLAPI_PLUGIN_FAILURE;
+    }
+
+    /* Now set the values into the config */
+    /* Are there some error cases here we should be checking? */
+    config = (struct addn_config *)slapi_ch_malloc(sizeof(struct addn_config));
+    config->default_suffix = slapi_entry_attr_get_charptr(plugin_entry, "addn_default_suffix");
+    config->filter_template = slapi_entry_attr_get_charptr(plugin_entry, "addn_filter");
+
+    /* Validate the filter_template only has one %s */
+    if (addn_filter_validate(config->filter_template) != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_start", "CRITICAL: Failed to validate addn_filter config entry!\n");
+        slapi_ch_free_string(&config->default_suffix);
+        slapi_ch_free_string(&config->filter_template);
+        slapi_ch_free((void **) &config);
+        return SLAPI_PLUGIN_FAILURE;
+    }
+
+    /* Set into the pblock */
+    slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, (void *) config);
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_start", "startup complete\n");
+
+    return LDAP_SUCCESS;
+}
+
+/*
+ * addn_close
+ *
+ * Called when the plugin is stopped. Frees the configs as needed
+ */
+int
+addn_close(Slapi_PBlock *pb)
+{
+    struct addn_config *config = NULL;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_close", "stopping ...\n");
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
+    if (config != NULL) {
+        slapi_ch_free_string(&config->default_suffix);
+        slapi_ch_free_string(&config->filter_template);
+        slapi_ch_free((void **) &config);
+        slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
+    }
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, "addn_close", "stop complete\n");
+
+    return LDAP_SUCCESS;
+}
+
+
+/*
+ * addn_init
+ *
+ * Initialise and register the addn plugin to the directory server.
+ */
+int
+addn_init(Slapi_PBlock *pb)
+{
+    int result = 0;
+
+    result = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+    if (result != LDAP_SUCCESS) {
+        goto out;
+    }
+
+    /* Get and stash our plugin identity */
+    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+
+    result = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&addn_description);
+    if (result != LDAP_SUCCESS) {
+        goto out;
+    }
+
+    result = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void*)addn_start);
+    if (result != LDAP_SUCCESS) {
+        goto out;
+    }
+
+    result = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void*)addn_close);
+    if (result != LDAP_SUCCESS) {
+        goto out;
+    }
+
+    result = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void*)addn_prebind);
+    if (result != LDAP_SUCCESS) {
+        goto out;
+    }
+
+out:
+    if (result == LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_init", "Success: plugin loaded.\n");
+        slapi_log_error(SLAPI_LOG_FATAL, "addn_init", "Warning: The use of this plugin violates the LDAPv3 specification RFC4511 section 4.2 BindDN specification. You have been warned ...\n");
+    } else {
+        slapi_log_error(SLAPI_LOG_PLUGIN, "addn_init", "Error: %d. \n", result);
+    }
+    return result;
+}
+
+
diff --git a/ldap/servers/plugins/addn/addn.h b/ldap/servers/plugins/addn/addn.h
new file mode 100644
index 0000000..6cac97c
--- /dev/null
+++ b/ldap/servers/plugins/addn/addn.h
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright (C) 2016 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * License: GPL (version 3 or any later version).
+ * See LICENSE for details. 
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/*
+ * AD DN bind plugin header
+ */
+
+#include "slapi-plugin.h"
+
+struct addn_config {
+    char *default_suffix;
+    char *filter_template;
+};
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index 0936478..12d6dca 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -858,6 +858,11 @@ account_locked:
         } else {
             /* even though preop failed, we should still call the post-op plugins */
             plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+            /* If the prebind plugins fail we MUST send a result!  */
+            /* Is there a way to get a better result descriptions from say the ADDN plugin? */
+            slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in failed\n");
+            send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+            goto free_and_return;
         }
     } else {
         send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
index 2842378..4cdd567 100644
--- a/ldap/servers/slapd/plugin.c
+++ b/ldap/servers/slapd/plugin.c
@@ -1785,7 +1785,10 @@ plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation, c
 					slapi_pblock_set(&(config[plugin_index].pb), SLAPI_PLUGIN, config[plugin_index].plugin);
 					ret = plugin_call_one( config[plugin_index].plugin, operation, &(config[plugin_index].pb));
 
-					pblock_done(&(config[plugin_index].pb));
+					/* We used to call pblock done here, bet we try to restart
+					 * the plugin. If we call done on the pb here, the next attempt
+					 * can have even MORE issues!
+					 */
 
 					if(ret)
 					{
@@ -1805,6 +1808,12 @@ plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation, c
 						plugin_set_plugins_started(config[plugin_index].plugin);
 					}
 
+					/* See above note about pblock done: Now we call it here
+					 * because at this point we *have* started correctly, so we
+					 * can now free this.
+					 */
+					pblock_done(&(config[plugin_index].pb));
+
 					/* Add this plugin to the shutdown list */
 
 					global_plugin_shutdown_order[shutdown_index] = config[plugin_index];
@@ -1828,7 +1837,7 @@ plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation, c
 							index++;
 						}	
 					}
-				} else {
+				} else { /* if (enabled) == false */
 					pblock_done(&(config[plugin_index].pb));
 				}
 
-- 
1.8.3.1

