From 57a6eeafe1f131ca77f9de437f462dc284455b2f Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Fri, 25 May 2012 12:26:02 -0400
Subject: [PATCH] Ticket #110 - RFE limiting root DN by host, IP, time of day, day of week

RFE Description:  There is no way to restrict when and where some one can attempt
                  root DN binds.  An intruder can brute force guess the password all
                  day long until they succeed, especailly if the DS is publicly
                  available.

Fix Description:  Created a new plugin, type "internalpreoperation" and an internal
                  preop bind function.  You can configure the plugin with some basic
                  access control:

            rootdn-open-time: 0800
            rootdn-close-time: 1700
            rootdn-days-allowed: Mon, Tue, Wed, Thu, Fri
            rootdn-allow-host: *.redhat.com
            rootdn-allow-host: *.fedora.com
            rootdn-deny-host: dangerous.boracle.com
            rootdn-allow-ip: 127.0.0.1
            rootdn-allow-ip: 2000:db8:de30::11
            rootdn-deny-ip: 192.168.1.*

                          As with our other ACL code, deny's always override the allow rules.

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

Reviewed by:
---
 Makefile.am                                        |   13 +-
 Makefile.in                                        |   50 ++-
 ldap/ldif/template-dse.ldif.in                     |   11 +
 ldap/servers/plugins/rootdn_access/rootdn_access.c |  663 ++++++++++++++++++++
 ldap/servers/plugins/rootdn_access/rootdn_access.h |   57 ++
 ldap/servers/slapd/bind.c                          |   34 +-
 ldap/servers/slapd/pblock.c                        |   14 +
 ldap/servers/slapd/plugin.c                        |   11 +-
 ldap/servers/slapd/slap.h                          |    2 +
 ldap/servers/slapd/slapi-plugin.h                  |    3 +
 10 files changed, 846 insertions(+), 12 deletions(-)
 create mode 100644 ldap/servers/plugins/rootdn_access/rootdn_access.c
 create mode 100644 ldap/servers/plugins/rootdn_access/rootdn_access.h

diff --git a/Makefile.am b/Makefile.am
index cf91842..d90cd4b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -205,7 +205,7 @@ serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
 	libreferint-plugin.la libreplication-plugin.la libretrocl-plugin.la \
 	libroles-plugin.la libstatechange-plugin.la libsyntax-plugin.la \
 	libviews-plugin.la libschemareload-plugin.la libusn-plugin.la \
-	libacctusability-plugin.la $(LIBACCTPOLICY_PLUGIN) \
+	libacctusability-plugin.la librootdn-access-plugin.la $(LIBACCTPOLICY_PLUGIN) \
 	$(LIBPAM_PASSTHRU_PLUGIN) $(LIBDNA_PLUGIN) \
 	$(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
 
@@ -822,6 +822,17 @@ libacl_plugin_la_LDFLAGS = -avoid-version
 libacl_plugin_la_LINK = $(CXXLINK) -avoid-version
 
 #------------------------
+# librootdn-access-plugin
+#------------------------
+#
+librootdn_access_plugin_la_SOURCES = ldap/servers/plugins/rootdn_access/rootdn_access.c
+
+librootdn_access_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+librootdn_access_plugin_la_LIBADD = libslapd.la $(NSPR_LINK)
+librootdn_access_plugin_la_LDFLAGS = -avoid-version
+
+
+#------------------------
 # libautomember-plugin
 #------------------------
 libautomember_plugin_la_SOURCES = ldap/servers/plugins/automember/automember.c
diff --git a/Makefile.in b/Makefile.in
index ab2f657..915e978 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -581,6 +581,15 @@ libroles_plugin_la_OBJECTS = $(am_libroles_plugin_la_OBJECTS)
 libroles_plugin_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(libroles_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+librootdn_access_plugin_la_DEPENDENCIES = libslapd.la \
+	$(am__DEPENDENCIES_1)
+am_librootdn_access_plugin_la_OBJECTS = ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo
+librootdn_access_plugin_la_OBJECTS =  \
+	$(am_librootdn_access_plugin_la_OBJECTS)
+librootdn_access_plugin_la_LINK = $(LIBTOOL) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(librootdn_access_plugin_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
 libschemareload_plugin_la_DEPENDENCIES = libslapd.la \
 	$(am__DEPENDENCIES_1)
 am_libschemareload_plugin_la_OBJECTS = ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.lo
@@ -1001,6 +1010,7 @@ SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libreferint_plugin_la_SOURCES) \
 	$(libreplication_plugin_la_SOURCES) \
 	$(libretrocl_plugin_la_SOURCES) $(libroles_plugin_la_SOURCES) \
+	$(librootdn_access_plugin_la_SOURCES) \
 	$(libschemareload_plugin_la_SOURCES) $(libslapd_la_SOURCES) \
 	$(libstatechange_plugin_la_SOURCES) \
 	$(libsyntax_plugin_la_SOURCES) $(libusn_plugin_la_SOURCES) \
@@ -1033,6 +1043,7 @@ DIST_SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libreferint_plugin_la_SOURCES) \
 	$(libreplication_plugin_la_SOURCES) \
 	$(libretrocl_plugin_la_SOURCES) $(libroles_plugin_la_SOURCES) \
+	$(librootdn_access_plugin_la_SOURCES) \
 	$(libschemareload_plugin_la_SOURCES) \
 	$(am__libslapd_la_SOURCES_DIST) \
 	$(libstatechange_plugin_la_SOURCES) \
@@ -1411,7 +1422,7 @@ serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
 	libreferint-plugin.la libreplication-plugin.la libretrocl-plugin.la \
 	libroles-plugin.la libstatechange-plugin.la libsyntax-plugin.la \
 	libviews-plugin.la libschemareload-plugin.la libusn-plugin.la \
-	libacctusability-plugin.la $(LIBACCTPOLICY_PLUGIN) \
+	libacctusability-plugin.la librootdn-access-plugin.la $(LIBACCTPOLICY_PLUGIN) \
 	$(LIBPAM_PASSTHRU_PLUGIN) $(LIBDNA_PLUGIN) \
 	$(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
 
@@ -1968,6 +1979,15 @@ libacl_plugin_la_LDFLAGS = -avoid-version
 libacl_plugin_la_LINK = $(CXXLINK) -avoid-version
 
 #------------------------
+# librootdn-access-plugin
+#------------------------
+#
+librootdn_access_plugin_la_SOURCES = ldap/servers/plugins/rootdn_access/rootdn_access.c
+librootdn_access_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+librootdn_access_plugin_la_LIBADD = libslapd.la $(NSPR_LINK)
+librootdn_access_plugin_la_LDFLAGS = -avoid-version
+
+#------------------------
 # libautomember-plugin
 #------------------------
 libautomember_plugin_la_SOURCES = ldap/servers/plugins/automember/automember.c
@@ -3784,6 +3804,17 @@ ldap/servers/plugins/roles/libroles_plugin_la-roles_plugin.lo:  \
 	ldap/servers/plugins/roles/$(DEPDIR)/$(am__dirstamp)
 libroles-plugin.la: $(libroles_plugin_la_OBJECTS) $(libroles_plugin_la_DEPENDENCIES) 
 	$(libroles_plugin_la_LINK) -rpath $(serverplugindir) $(libroles_plugin_la_OBJECTS) $(libroles_plugin_la_LIBADD) $(LIBS)
+ldap/servers/plugins/rootdn_access/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/rootdn_access
+	@: > ldap/servers/plugins/rootdn_access/$(am__dirstamp)
+ldap/servers/plugins/rootdn_access/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/rootdn_access/$(DEPDIR)
+	@: > ldap/servers/plugins/rootdn_access/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo:  \
+	ldap/servers/plugins/rootdn_access/$(am__dirstamp) \
+	ldap/servers/plugins/rootdn_access/$(DEPDIR)/$(am__dirstamp)
+librootdn-access-plugin.la: $(librootdn_access_plugin_la_OBJECTS) $(librootdn_access_plugin_la_DEPENDENCIES) 
+	$(librootdn_access_plugin_la_LINK) -rpath $(serverplugindir) $(librootdn_access_plugin_la_OBJECTS) $(librootdn_access_plugin_la_LIBADD) $(LIBS)
 ldap/servers/plugins/schema_reload/$(am__dirstamp):
 	@$(MKDIR_P) ldap/servers/plugins/schema_reload
 	@: > ldap/servers/plugins/schema_reload/$(am__dirstamp)
@@ -5017,6 +5048,8 @@ mostlyclean-compile:
 	-rm -f ldap/servers/plugins/roles/libroles_plugin_la-roles_cache.lo
 	-rm -f ldap/servers/plugins/roles/libroles_plugin_la-roles_plugin.$(OBJEXT)
 	-rm -f ldap/servers/plugins/roles/libroles_plugin_la-roles_plugin.lo
+	-rm -f ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.$(OBJEXT)
+	-rm -f ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo
 	-rm -f ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.$(OBJEXT)
 	-rm -f ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.lo
 	-rm -f ldap/servers/plugins/statechange/libstatechange_plugin_la-statechange.$(OBJEXT)
@@ -5714,6 +5747,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/rever/$(DEPDIR)/libdes_plugin_la-rever.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/roles/$(DEPDIR)/libroles_plugin_la-roles_cache.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/roles/$(DEPDIR)/libroles_plugin_la-roles_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/rootdn_access/$(DEPDIR)/librootdn_access_plugin_la-rootdn_access.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/schema_reload/$(DEPDIR)/libschemareload_plugin_la-schema_reload.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/statechange/$(DEPDIR)/libstatechange_plugin_la-statechange.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-bin.Plo@am__quote@
@@ -7758,6 +7792,13 @@ ldap/servers/plugins/roles/libroles_plugin_la-roles_plugin.lo: ldap/servers/plug
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libroles_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/roles/libroles_plugin_la-roles_plugin.lo `test -f 'ldap/servers/plugins/roles/roles_plugin.c' || echo '$(srcdir)/'`ldap/servers/plugins/roles/roles_plugin.c
 
+ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo: ldap/servers/plugins/rootdn_access/rootdn_access.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librootdn_access_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo -MD -MP -MF ldap/servers/plugins/rootdn_access/$(DEPDIR)/librootdn_access_plugin_la-rootdn_access.Tpo -c -o ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo `test -f 'ldap/servers/plugins/rootdn_access/rootdn_access.c' || echo '$(srcdir)/'`ldap/servers/plugins/rootdn_access/rootdn_access.c
+@am__fastdepCC_TRUE@	$(am__mv) ldap/servers/plugins/rootdn_access/$(DEPDIR)/librootdn_access_plugin_la-rootdn_access.Tpo ldap/servers/plugins/rootdn_access/$(DEPDIR)/librootdn_access_plugin_la-rootdn_access.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/plugins/rootdn_access/rootdn_access.c' object='ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librootdn_access_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/rootdn_access/librootdn_access_plugin_la-rootdn_access.lo `test -f 'ldap/servers/plugins/rootdn_access/rootdn_access.c' || echo '$(srcdir)/'`ldap/servers/plugins/rootdn_access/rootdn_access.c
+
 ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.lo: ldap/servers/plugins/schema_reload/schema_reload.c
 @am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libschemareload_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.lo -MD -MP -MF ldap/servers/plugins/schema_reload/$(DEPDIR)/libschemareload_plugin_la-schema_reload.Tpo -c -o ldap/servers/plugins/schema_reload/libschemareload_plugin_la-schema_reload.lo `test -f 'ldap/servers/plugins/schema_reload/schema_reload.c' || echo '$(srcdir)/'`ldap/servers/plugins/schema_reload/schema_reload.c
 @am__fastdepCC_TRUE@	$(am__mv) ldap/servers/plugins/schema_reload/$(DEPDIR)/libschemareload_plugin_la-schema_reload.Tpo ldap/servers/plugins/schema_reload/$(DEPDIR)/libschemareload_plugin_la-schema_reload.Plo
@@ -9779,6 +9820,7 @@ clean-libtool:
 	-rm -rf ldap/servers/plugins/retrocl/.libs ldap/servers/plugins/retrocl/_libs
 	-rm -rf ldap/servers/plugins/rever/.libs ldap/servers/plugins/rever/_libs
 	-rm -rf ldap/servers/plugins/roles/.libs ldap/servers/plugins/roles/_libs
+	-rm -rf ldap/servers/plugins/rootdn_access/.libs ldap/servers/plugins/rootdn_access/_libs
 	-rm -rf ldap/servers/plugins/schema_reload/.libs ldap/servers/plugins/schema_reload/_libs
 	-rm -rf ldap/servers/plugins/statechange/.libs ldap/servers/plugins/statechange/_libs
 	-rm -rf ldap/servers/plugins/syntaxes/.libs ldap/servers/plugins/syntaxes/_libs
@@ -10425,6 +10467,8 @@ distclean-generic:
 	-rm -f ldap/servers/plugins/rever/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/roles/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/roles/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/rootdn_access/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/rootdn_access/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/schema_reload/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/schema_reload/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/statechange/$(DEPDIR)/$(am__dirstamp)
@@ -10475,7 +10519,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/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/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(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/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/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/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(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
@@ -10531,7 +10575,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/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/schema_reload/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(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/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/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/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(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/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
index 5107d72..ddf2b35 100644
--- a/ldap/ldif/template-dse.ldif.in
+++ b/ldap/ldif/template-dse.ldif.in
@@ -734,6 +734,17 @@ nsslapd-plugintype: object
 nsslapd-pluginenabled: off
 nsslapd-plugin-depends-on-type: database
 
+dn: cn=RootDN Access Control,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: RootDN Access Control
+nsslapd-pluginpath: librootdn-access-plugin.so
+nsslapd-plugininitfunc: rootdn_init
+nsslapd-plugintype: internalpreoperation
+nsslapd-pluginenabled: off
+nsslapd-plugin-depends-on-type: database
+
 dn: cn=ldbm database,cn=plugins,cn=config
 objectclass: top
 objectclass: nsSlapdPlugin
diff --git a/ldap/servers/plugins/rootdn_access/rootdn_access.c b/ldap/servers/plugins/rootdn_access/rootdn_access.c
new file mode 100644
index 0000000..7fb5615
--- /dev/null
+++ b/ldap/servers/plugins/rootdn_access/rootdn_access.c
@@ -0,0 +1,663 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/*
+ *  Root DN Access Control plug-in
+ */
+#include "rootdn_access.h"
+#include <nspr.h>
+#include <time.h>
+#include <ctype.h>
+
+/*
+ * Add an entry like the following to dse.ldif to enable this plugin:
+ *
+ *   dn: cn=RootDN Access Control,cn=plugins,cn=config
+ *   objectclass: top
+ *   objectclass: nsSlapdPlugin
+ *   objectclass: extensibleObject
+ *   cn: RootDN Access Control
+ *   nsslapd-pluginpath: librootdn-access-plugin.so
+ *   nsslapd-plugininitfunc: rootdn_init
+ *   nsslapd-plugintype: rootdnpreoperation
+ *   nsslapd-pluginenabled: on
+ *   nsslapd-plugin-depends-on-type: database
+ *   nsslapd-pluginid: rootdn-access-control
+ *   rootdn-open-time: 0800
+ *   rootdn-close-time: 1700
+ *   rootdn-days-allowed: Mon, Tue, Wed, Thu, Fri
+ *   rootdn-allow-host: *.redhat.com
+ *   rootdn-allow-host: *.fedora.com
+ *   rootdn-deny-host: dangerous.boracle.com
+ *   rootdn-allow-ip: 127.0.0.1
+ *   rootdn-allow-ip: 2000:db8:de30::11
+ *   rootdn-deny-ip: 192.168.1.*
+ *
+ */
+
+/*
+ *  Plugin Functions
+ */
+int rootdn_init(Slapi_PBlock *pb);
+static int rootdn_start(Slapi_PBlock *pb);
+static int rootdn_load_config(Slapi_PBlock *pb);
+static int rootdn_check_access(Slapi_PBlock *pb);
+static int rootdn_check_host_wildcard(char *host, char *client_host);
+static int rootdn_check_ip_wildcard(char *ip, char *client_ip);
+static int rootdn_preop_bind_init(Slapi_PBlock *pb);
+char * strToLower(char *str);
+
+/*
+ * Plug-in globals
+ */
+static void *_PluginID = NULL;
+static char *_PluginDN = NULL;
+static int g_plugin_started = 0;
+static int open_time = 0;
+static int close_time = 0;
+static char *daysAllowed = NULL;
+static char **hosts = NULL;
+static char **hosts_to_deny = NULL;
+static char **ips = NULL;
+static char **ips_to_deny = NULL;
+
+static Slapi_PluginDesc pdesc = { ROOTDN_FEATURE_DESC,
+                                  VENDOR,
+                                  DS_PACKAGE_VERSION,
+                                  ROOTDN_PLUGIN_DESC };
+
+/*
+ * Plugin identity functions
+ */
+void
+rootdn_set_plugin_id(void *pluginID)
+{
+    _PluginID = pluginID;
+}
+
+void *
+rootdn_get_plugin_id()
+{
+    return _PluginID;
+}
+
+void
+rootdn_set_plugin_dn(char *pluginDN)
+{
+    _PluginDN = pluginDN;
+}
+
+char *
+rootdn_get_plugin_dn()
+{
+    return _PluginDN;
+}
+
+
+int
+rootdn_init(Slapi_PBlock *pb){
+    int status = 0;
+    char *plugin_identity = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ROOTDN_PLUGIN_SUBSYSTEM,
+                    "--> rootdn_init\n");
+
+    /* Store the plugin identity for later use.  Used for internal operations. */
+    slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+    PR_ASSERT(plugin_identity);
+    rootdn_set_plugin_id(plugin_identity);
+
+    /* Register callbacks */
+    if(slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
+       slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *) rootdn_start) != 0 ||
+       slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0 )
+    {
+        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_init: failed to register plugin\n");
+        status = -1;
+    }
+
+    /* for this plugin we don't want to skip over root dn's when binding */
+    slapi_set_plugin_open_rootdn_bind(pb);
+
+    if (!status &&
+        slapi_register_plugin("internalpreoperation",            /* op type */
+                              1,                                 /* Enabled */
+                              "rootdn_preop_bind_init", /* this function desc */
+                              rootdn_preop_bind_init,   /* init func */
+                              ROOTDN_PLUGIN_DESC,                /* plugin desc */
+                              NULL,                              /* ? */
+                              plugin_identity                    /* access control */
+        )) {
+        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM,
+                        "rootdn_init: failed to register rootdn preoperation plugin\n");
+        status = -1;
+    }
+
+    /*
+     *  Load the config
+     */
+    if(rootdn_load_config(pb) != 0){
+        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM,
+            "rootdn_start: unable to load plug-in configuration\n");
+        return -1;
+    }
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM,"<-- rootdn_init\n");
+    return status;
+}
+
+static int
+rootdn_preop_bind_init(Slapi_PBlock *pb)
+{
+    if(slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN, (void *) rootdn_check_access) != 0){
+        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM,"rootdn_preop_bind_init: "
+            "failed to register function\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+rootdn_start(Slapi_PBlock *pb){
+    /* Check if we're already started */
+    if (g_plugin_started) {
+        goto done;
+    }
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "--> rootdn_start\n");
+
+    g_plugin_started = 1;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "<-- rootdn_start\n");
+
+done:
+    return 0;
+}
+
+static int
+rootdn_load_config(Slapi_PBlock *pb)
+{
+    Slapi_Entry *e = NULL;
+    char *openTime, *closeTime;
+    char hour[3], min[3];
+    int result = 0;
+    int i;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "--> rootdn_load_config\n");
+
+    if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &e) == 0) && e){
+        /*
+         *  Grab our plugin settings
+         */
+        openTime = slapi_entry_attr_get_charptr(e, "rootdn-open-time");
+        closeTime = slapi_entry_attr_get_charptr(e, "rootdn-close-time");
+        daysAllowed = slapi_entry_attr_get_charptr(e, "rootdn-days-allowed");
+        hosts = slapi_entry_attr_get_charray(e, "rootdn-allow-host");
+        hosts_to_deny = slapi_entry_attr_get_charray(e, "rootdn-deny-host");
+        ips = slapi_entry_attr_get_charray(e, "rootdn-allow-ip");
+        ips_to_deny = slapi_entry_attr_get_charray(e, "rootdn-deny-ip");
+        /*
+         *  Validate out settings
+         */
+        if(daysAllowed){
+            if(strcspn(daysAllowed, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ,")){
+                slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                    "invalid rootdn-days-allowed value (%s), must be all letters, and comma separators\n",closeTime);
+                slapi_ch_free_string(&daysAllowed);
+                return -1;
+            }
+            daysAllowed = strToLower(daysAllowed);
+        }
+        if(openTime){
+            if (strcspn(openTime, "0123456789")){
+                slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                    "invalid rootdn-open-time value (%s), must be all digits\n",openTime);
+                slapi_ch_free_string(&openTime);
+                return -1;
+            }
+            if(strlen(openTime) != 4){
+                slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                    "invalid format for rootdn-open-time value (%s).  Should be HHMM\n", openTime);
+                slapi_ch_free_string(&openTime);
+                return -1;
+            }
+            /*
+             *  convert the time to all seconds
+             */
+            strncpy(hour, openTime,2);
+            strncpy(min, openTime+2,2);
+            open_time = (atoi(hour) * 3600) + (atoi(min) * 60);
+        }
+        if(closeTime){
+            if (strcspn(closeTime, "0123456789")){
+                slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                    "invalid rootdn-open-time value (%s), must be all digits, and should be HHMM\n",closeTime);
+                slapi_ch_free_string(&closeTime);
+                return -1;
+            }
+            if(strlen(closeTime) != 4){
+                slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                    "invalid format for rootdn-open-time value (%s), should be HHMM\n", closeTime);
+                slapi_ch_free_string(&closeTime);
+                return -1;
+            }
+            /*
+             *  convert the time to all seconds
+             */
+
+            strncpy(hour, closeTime,2);
+            strncpy(min, closeTime+2,2);
+            close_time = (atoi(hour) * 3600) + (atoi(min) * 60);
+        }
+        if((openTime && closeTime == NULL) || (openTime == NULL && closeTime)){
+            /* If you are using TOD access control, you must have a open and close time */
+            slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                "there must be a open and a close time\n");
+            slapi_ch_free_string(&closeTime);
+            slapi_ch_free_string(&openTime);
+            return -1;
+        }
+        if(close_time && open_time && close_time <= open_time){
+            /* Make sure the closing time is greater than the open time */
+            slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                "the close time must be greater than the open time\n");
+            result = -1;
+        }
+        if(hosts){
+            for(i = 0; hosts[i] != NULL; i++){
+                if(strcspn(hosts[i], "0123456789.*-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")){
+                    slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                        "hostname (%s) contians invalid characters, skipping\n",hosts[i]);
+                    slapi_ch_free_string(&hosts[i]);
+                    hosts[i] = slapi_ch_strdup("!invalid");
+                    continue;
+                }
+            }
+        }
+        if(hosts_to_deny){
+            for(i = 0; hosts_to_deny[i] != NULL; i++){
+                if(strcspn(hosts_to_deny[i], "0123456789.*-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")){
+                    slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                        "hostname (%s) contians invalid characters, skipping\n",hosts_to_deny[i]);
+                    slapi_ch_free_string(&hosts_to_deny[i]);
+                    hosts_to_deny[i] = slapi_ch_strdup("!invalid");
+                    continue;
+                }
+            }
+        }
+        if(ips){
+            for(i = 0; ips[i] != NULL; i++){
+                if(strcspn(ips[i], "0123456789:ABCDEFabcdef.*")){
+                    slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                        "IP address contains invalid characters (%s), skipping\n", ips[i]);
+                    slapi_ch_free_string(&ips[i]);
+                    ips[i] = slapi_ch_strdup("!invalid");
+                    continue;
+                }
+                if(strstr(ips[i],":") == 0){
+                    /*
+                     *  IPv4 - make sure it's just numbers, dots, and wildcard
+                     */
+                    if(strcspn(ips[i], "0123456789.*")){
+                        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                            "IPv4 address contains invalid characters (%s), skipping\n", ips[i]);
+                        slapi_ch_free_string(&ips[i]);
+                        ips[i] = slapi_ch_strdup("!invalid");
+                        continue;
+                    }
+                }
+            }
+        }
+        if(ips_to_deny){
+            for(i = 0; ips_to_deny[i] != NULL; i++){
+                if(strcspn(ips_to_deny[i], "0123456789:ABCDEFabcdef.*")){
+                    slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                        "IP address contains invalid characters (%s), skipping\n", ips_to_deny[i]);
+                    slapi_ch_free_string(&ips_to_deny[i]);
+                    ips_to_deny[i] = slapi_ch_strdup("!invalid");
+                    continue;
+                }
+                if(strstr(ips_to_deny[i],":") == 0){
+                    /*
+                     *  IPv4 - make sure it's just numbers, dots, and wildcard
+                     */
+                    if(strcspn(ips_to_deny[i], "0123456789.*")){
+                        slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
+                            "IPv4 address contains invalid characters (%s), skipping\n", ips_to_deny[i]);
+                        slapi_ch_free_string(&ips_to_deny[i]);
+                        ips_to_deny[i] = slapi_ch_strdup("!invalid");
+                        continue;
+                    }
+                }
+            }
+        }
+        slapi_ch_free_string(&openTime);
+        slapi_ch_free_string(&closeTime);
+    } else {
+        /* failed to get the plugin entry */
+        result = -1;
+    }
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "<-- rootdn_load_config (%d)\n", result);
+
+    return result;
+}
+
+
+static int
+rootdn_check_access(Slapi_PBlock *pb){
+    PRNetAddr *client_addr = NULL;
+    PRHostEnt *host_entry = NULL;
+    time_t  curr_time;
+    struct tm *timeinfo;
+    char *dnsName = NULL;
+    int isRoot = 0;
+    int rc = 0;
+    int i;
+
+    /*
+     *  Verify this is a root DN
+     */
+    slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
+    if(!isRoot){
+    	return 0;
+    }
+    /*
+     *  grab the current time/info if we need it
+     */
+    if(open_time || daysAllowed){
+        time(&curr_time);
+        timeinfo = localtime(&curr_time);
+    }
+    /*
+     *  First check TOD restrictions, continue through if we are in the open "window"
+     */
+    if(open_time){
+        int curr_total;
+
+        curr_total = (timeinfo->tm_hour * 3600) + (timeinfo->tm_min * 60);
+
+        if((curr_total < open_time) || (curr_total >= close_time)){
+            slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: bind not in the "
+                "allowed time window\n");
+            return -1;
+        }
+    }
+    /*
+     *  Check if today is an allowed day
+     */
+    if(daysAllowed){
+        char *timestr;
+        char day[4];
+        char *today = day;
+
+        timestr = asctime(timeinfo); // DDD MMM dd hh:mm:ss YYYY
+        memmove(day, timestr, 3); // we only want the day
+        today = strToLower(today);
+
+        if(!strstr(today, daysAllowed)){
+            slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: bind not allowed for today\n");
+            return -1;
+        }
+    }
+    /*
+     *  Check the host restrictions, deny always overrides allow
+     */
+    if(hosts || hosts_to_deny){
+        char buf[PR_NETDB_BUF_SIZE];
+        char *host;
+
+        /*
+         *  Get the client address
+         */
+        client_addr = (PRNetAddr *)slapi_ch_malloc(sizeof(PRNetAddr));
+        if ( slapi_pblock_get( pb, SLAPI_CONN_CLIENTNETADDR, client_addr ) != 0 ) {
+            slapi_log_error( SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: Could not get client address for hosts.\n" );
+            rc = -1;
+            goto free_and_return;
+        }
+        /*
+         *  Get the hostname from the client address
+         */
+        host_entry = (PRHostEnt *)slapi_ch_malloc( sizeof(PRHostEnt) );
+        if ( PR_GetHostByAddr(client_addr, buf, sizeof(buf), host_entry ) == PR_SUCCESS ) {
+            if ( host_entry->h_name != NULL ) {
+                /* copy the hostname */
+                dnsName = slapi_ch_strdup( host_entry->h_name );
+            } else {
+                /* no hostname */
+                slapi_log_error( SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: client address missing hostname\n");
+                rc = -1;
+                goto free_and_return;
+            }
+        } else {
+            slapi_log_error( SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: client IP address could not be resolved\n");
+            rc = -1;
+            goto free_and_return;
+        }
+        /*
+         *  Now we have our hostname, now do our checks
+         */
+        if(hosts_to_deny){
+            for(i = 0; hosts_to_deny[i] != NULL; i++){
+                host = hosts_to_deny[i];
+                /* check for wild cards */
+                if(host[0] == '*'){
+                    if(rootdn_check_host_wildcard(host, dnsName) == 0){
+                        /* match, return failure */
+                        rc = -1;
+                        goto free_and_return;
+                    }
+                } else {
+                    if(strcasecmp(host,dnsName) == 0){
+                        /* we have a match, return failure */
+                        rc = -1;
+                        goto free_and_return;
+                    }
+                }
+            }
+            rc = 0;
+        }
+        if(hosts){
+            for(i = 0; hosts[i] != NULL; i++){
+                host = hosts[i];
+                /* check for wild cards */
+                if(host[0] == '*'){
+                    if(rootdn_check_host_wildcard(host, dnsName) == 0){
+                        /* match */
+                        rc = 0;
+                        goto free_and_return;
+                    }
+                } else {
+                    if(strcasecmp(host,dnsName) == 0){
+                        /* we have a match, */
+                        rc = 0;
+                        goto free_and_return;
+                    }
+                }
+            }
+            rc = -1;
+        }
+    }
+    /*
+     *  Check the IP address restrictions, deny always overrides allow
+     */
+    if(ips || ips_to_deny){
+        char ip_str[256];
+        char *ip;
+        int ip_len, i;
+
+        if(client_addr == NULL){
+            client_addr = (PRNetAddr *)slapi_ch_malloc(sizeof(PRNetAddr));
+            if ( slapi_pblock_get( pb, SLAPI_CONN_CLIENTNETADDR, client_addr ) != 0 ) {
+                slapi_log_error( SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: Could not get client address for IP.\n" );
+                rc = -1;
+                goto free_and_return;
+            }
+        }
+        /*
+         *  Check if we are IPv4, so we can grab the correct IP addr for "ip_str"
+         */
+        if ( PR_IsNetAddrType( client_addr, PR_IpAddrV4Mapped ) ) {
+   	        PRNetAddr v4addr;
+   	        memset( &v4addr, 0, sizeof( v4addr ) );
+   	        v4addr.inet.family = PR_AF_INET;
+   	        v4addr.inet.ip = client_addr->ipv6.ip.pr_s6_addr32[3];
+   	        if( PR_NetAddrToString( &v4addr, ip_str, sizeof( ip_str )) != PR_SUCCESS){
+   	            slapi_log_error( SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: Could not get IPv4 from client address.\n" );
+                rc = -1;
+                goto free_and_return;
+   	        }
+        } else {
+            if( PR_NetAddrToString(client_addr, ip_str, sizeof(ip_str)) != PR_SUCCESS){
+                slapi_log_error( SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_check_access: Could not get IPv6 from client address.\n" );
+                rc = -1;
+                goto free_and_return;
+            }
+        }
+        /*
+         *  Now we have our IP address, do our checks
+         */
+        if(ips_to_deny){
+            for(i = 0; ips_to_deny[i] != NULL; i++){
+                ip = ips_to_deny[i];
+                ip_len = strlen(ip);
+                if(ip[ip_len - 1] == '*'){
+                    if(rootdn_check_ip_wildcard(ips_to_deny[i], ip_str) == 0){
+                        /* match, return failure */
+                    	rc = -1;
+                    	goto free_and_return;
+                    }
+                } else {
+                    if(strcasecmp(ip_str, ip)==0){
+                    	/* match, return failure */
+                    	rc = -1;
+                    	goto free_and_return;
+                    }
+                }
+            }
+            rc = 0;
+        }
+        if(ips){
+            for(i = 0; ips[i] != NULL; i++){
+                ip = ips[i];
+                ip_len = strlen(ip);
+                if(ip[ip_len - 1] == '*'){
+                    if(rootdn_check_ip_wildcard(ip, ip_str) == 0){
+                        /* match, return success */
+                        rc = 0;
+                        goto free_and_return;
+                    }
+                } else {
+                    if(strcasecmp(ip_str, ip)==0){
+                        /* match, return success */
+                        rc = 0;
+                        goto free_and_return;
+                    }
+                }
+            }
+            rc = -1;
+        }
+    }
+
+free_and_return:
+    slapi_ch_free((void **)&client_addr);
+    slapi_ch_free((void **)&host_entry);
+    slapi_ch_free_string(&dnsName);
+
+    return rc;
+}
+
+static int
+rootdn_check_host_wildcard(char *host, char *client_host)
+{
+    int host_len = strlen(host);
+    int client_len = strlen(client_host);
+    int i, j;
+    /*
+     *  Start at the end of the string and move backwards, and skip the first char "*"
+     */
+    if(client_len < host_len){
+        /* this can't be a match */
+        return -1;
+    }
+    for(i = host_len - 1, j = client_len - 1; i > 0; i--, j--){
+        if(host[i] != client_host[j]){
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int
+rootdn_check_ip_wildcard(char *ip, char *client_ip)
+{
+    int ip_len = strlen(ip);
+    int i;
+    /*
+     *  Start at the beginning of the string and move forward, and skip the last char "*"
+     */
+    if(strlen(client_ip) < ip_len){
+        /* this can't be a match */
+        return -1;
+    }
+    for(i = 0; i < ip_len - 1; i++){
+        if(ip[i] != client_ip[i]){
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+char *
+strToLower(char *str){
+    int i;
+
+    for(i = 0; i < strlen(str); i++){
+        str[i] = tolower(str[i]);
+    }
+    return str;
+}
+
+
diff --git a/ldap/servers/plugins/rootdn_access/rootdn_access.h b/ldap/servers/plugins/rootdn_access/rootdn_access.h
new file mode 100644
index 0000000..80b8d4a
--- /dev/null
+++ b/ldap/servers/plugins/rootdn_access/rootdn_access.h
@@ -0,0 +1,57 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/*
+ *  Root DN access control plug-in header file
+ */
+#include "slapi-plugin.h"
+#include <nspr.h>
+#include <time.h>
+#include <ctype.h>
+
+#define ROOTDN_PLUGIN_SUBSYSTEM  "rootdn-access-control-plugin"
+#define ROOTDN_FEATURE_DESC      "Root DN Access Control"
+#define ROOTDN_PLUGIN_DESC       "Root DN Access Control plugin"
+#define ROOTDN_PLUGIN_TYPE_DESC  "Root DN Access Control plugin"
+
+
+
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index d725d5c..d4d3b49 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -614,21 +614,41 @@ do_bind( Slapi_PBlock *pb )
             Slapi_Value cv;
             slapi_value_init_berval(&cv,&cred);
 
-            /* right dn and passwd - authorize */
+            /*
+             *  Call pre bind root dn plugin for checking root dn access control.
+             *
+             *  Do this before checking the password so that we give a consistent error,
+             *  regardless if the password is correct or not.  Or else it would still be
+             *  possible to brute force guess the password even though access would still
+             *  be denied.
+             */
+            if (plugin_call_plugins(pb, SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN) != 0){
+                send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+                    "RootDN access control violation", 0, NULL );
+                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
+                value_done(&cv);
+                goto free_and_return;
+            }
+            /*
+             *  Check the dn and password
+             */
             if ( is_root_dn_pw( slapi_sdn_get_ndn(sdn), &cv )) {
-                bind_credentials_set( pb->pb_conn, SLAPD_AUTH_SIMPLE,
-                                      slapi_ch_strdup( slapi_sdn_get_ndn(sdn) ),
+                /*
+                 *  right dn and passwd - authorize
+                 */
+                bind_credentials_set( pb->pb_conn, SLAPD_AUTH_SIMPLE, slapi_ch_strdup(slapi_sdn_get_ndn(sdn)),
                                       NULL, NULL, NULL , NULL);
-
-            /* right dn, wrong passwd - reject with invalid creds */
             } else {
-                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
-                                  NULL, 0, NULL );
+            	/*
+                 *  right dn, wrong passwd - reject with invalid credentials
+                 */
+                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
                 /* increment BindSecurityErrorcount */
                 slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
                 value_done(&cv);
                 goto free_and_return;
             }
+
             value_done(&cv);
         }
 
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 76c031a..4be8efd 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1062,6 +1062,14 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 		(*(IFP *)value) = pblock->pb_plugin->plg_internal_post_delete;
 		break;
 
+	/* rootDN pre bind operation plugin */
+	case SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN:
+		if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_internal_pre_bind;
+		break;
+
 	/* backend pre txn operation plugin */
 	case SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN:
 		if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) {
@@ -2620,6 +2628,12 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 		}
 		pblock->pb_plugin->plg_internal_pre_delete = (IFP) value;
 		break;
+	case SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN:
+		if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_internal_pre_bind = (IFP) value;
+		break;
 
 	/* internal postoperation plugin */
 	case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN:
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
index 8aa95ac..436cc02 100644
--- a/ldap/servers/slapd/plugin.c
+++ b/ldap/servers/slapd/plugin.c
@@ -363,6 +363,7 @@ plugin_call_plugins( Slapi_PBlock *pb, int whichfunction )
 	case SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN:
 	case SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN:
 	case SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN:
+	case SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN:
         plugin_list_number= PLUGIN_LIST_INTERNAL_PREOPERATION;
 		break;
 	case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN:
@@ -387,6 +388,7 @@ plugin_call_plugins( Slapi_PBlock *pb, int whichfunction )
 		do_op = 1; /* always allow backend callbacks (even during startup) */
 		break;
 	}
+
 	if(plugin_list_number!=-1 && do_op)
 	{
 	    /* We stash the pblock plugin pointer to preserve the callers context */
@@ -1705,7 +1707,7 @@ plugin_get_type_and_list(
 	} else if ( strcasecmp( plugintype, "index" ) == 0 ) {
         *type = SLAPI_PLUGIN_INDEX;
         plugin_list_index= PLUGIN_LIST_INDEX;
-    } else {
+	} else {
 		return( 1 );	/* unknown plugin type - pass to backend */
 	}
 
@@ -3205,3 +3207,10 @@ slapi_get_plugin_default_config(char *type, Slapi_ValueSet **valueset)
 
     return rc;
 }
+
+void
+slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb){
+	struct pluginconfig *config = &pb->pb_plugin->plg_conf;
+
+	ptd_set_special_data(&(config->plgc_bind_subtrees), PLGC_DATA_BIND_ROOT);
+}
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 22237ce..672c361 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1004,11 +1004,13 @@ struct slapdplugin {
 			IFP	plg_un_internal_pre_modrdn;	  /* modrdn */
 			IFP	plg_un_internal_pre_add;		  /* add */
 			IFP	plg_un_internal_pre_delete;	  /* delete */
+			IFP	plg_un_internal_pre_bind;	  /* bind */
 		} plg_un_internal_pre;
 #define plg_internal_pre_modify	plg_un.plg_un_internal_pre.plg_un_internal_pre_modify
 #define plg_internal_pre_modrdn	plg_un.plg_un_internal_pre.plg_un_internal_pre_modrdn
 #define plg_internal_pre_add	plg_un.plg_un_internal_pre.plg_un_internal_pre_add
 #define plg_internal_pre_delete	plg_un.plg_un_internal_pre.plg_un_internal_pre_delete
+#define plg_internal_pre_bind	plg_un.plg_un_internal_pre.plg_un_internal_pre_bind
 
 		/* internal post-operation plugin structure */
 		struct plg_un_internal_post_operation {
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 823652a..63c37f0 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6305,6 +6305,7 @@ typedef struct slapi_plugindesc {
 #define SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN	421
 #define SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN	422
 #define SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN	423
+#define SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN	424
 
 /* preoperation plugin to the backend */
 #define SLAPI_PLUGIN_BE_PRE_ADD_FN		450
@@ -7078,6 +7079,8 @@ uint32_t slapi_str_to_u32(const char *s);
  */
 uint64_t slapi_str_to_u64(const char *s);
 
+void slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.7.1

