Blob Blame History Raw
diff --git a/Makefile.am b/Makefile.am
index f5ff369..31ba5d6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,4 +2,4 @@ ACLOCAL_AMFLAGS = -I m4
 
 SUBDIRS = doc src
 
-doc_DATA = README NEWS
+dist_doc_DATA = README.md NEWS COPYING
diff --git a/NEWS b/NEWS
index 12aa18a..8fac0dd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+11.0
+====
+[1] The plugin was ported to BIND 9.11. Minimal BIND version is now 9.11.0rc1.
+    https://fedorahosted.org/bind-dyndb-ldap/ticket/161
+
+[2] Configuration format in named.conf is different
+    and incompatible with all previous versions. Please see README.md.
+
+[3] Obsolete plugin options were removed:
+    cache_ttl, psearch, serial_autoincrement, zone_refresh.
+
 10.1
 ====
 [1] Prevent crash while reloading previously invalid but now valid DNS zone.
diff --git a/README b/README
deleted file mode 100644
index 2fd09b5..0000000
--- a/README
+++ /dev/null
@@ -1,539 +0,0 @@
-1. Introduction
-===============
-
-The dynamic LDAP back-end is a plug-in for BIND that provides an LDAP
-database back-end capabilities. For now, it requires that BIND is patched
-to support dynamic loading of database back-ends. You can get a patch
-for your version here:
-
-  https://github.com/pspacek/bind-dynamic_db
-
-Hopefully, the patch will once be included in the official BIND release.
-
-BIND >= 9.9.0 is required.
-
-2. Features
-===========
-
-* support for dynamic updates
-* SASL authentication
-* SyncRepl (RFC 4533) for run-time synchronization with LDAP server
-* read-query performance nearly same as with plain BIND
-* AXFR and IXFR zone transfers are supported
-* DNSSEC in-line signing is supported, including dynamic updates
-
-
-3. Installation
-===============
-
-To install the LDAP back-end, extract the tarball and go to the unpacked
-directory. Then follow these steps:
-
-$ ./configure --libdir=<libdir>
-$ make
-
-Where <libdir> is a directory where your libdns is installed. This is
-typically going to be /usr/lib or /usr/lib64 on 64 bit systems.
-
-If configure script complains that it "Can't obtain libdns version",
-please verify you have installed bind development files (package bind9-dev
-or bind-devel) and you exported correct CPPFLAGS via
-"export CPPFLAGS=`isc-config.sh --cflags`" command.
-
-Then, to install, run this as root:
-# make install
-
-This will install the file ldap.so into the <libdir>/bind/ directory.
-
-Alternatively, the latest version can be obtained from Git repository.
-You can use following commands to prepare latest source tree for compilation:
-
-$ git clone https://git.fedorahosted.org/git/bind-dyndb-ldap.git
-$ cd bind-dyndb-ldap
-$ autoreconf -fvi
-
-4. LDAP schema
-==============
-
-You can find the complete LDAP schema in the documentation directory. An
-example zone ldif is available in the doc directory.
-
-4.1 Master zone (idnsZone)
---------------------------
-Object class idnsZone is equivalent to type "master" statement in named.conf.
-
-Attributes:
-* idnsAllowDynUpdate
-	Allow dynamic update of records in this zone. If attribute doesn't exist,
-	value "dyn_update" from plugin configuration will be used.
-
-* idnsAllowQuery
-	Specifies BIND9 zone ACL element as one string.
-
-	Example 1:      idnsAllowQuery: 192.0.2.1;
-	In the first example above, only the client with 192.0.2.1 IP address
-	is allowed to query records from the zone.
-
-	Example 2:      idnsAllowQuery: !192.0.2.33; 192.0.2.0/24;
-	In the second example, queries from client 192.0.2.33 are refused
-	but queries from all other clients in the 192.0.2.0/24 network
-	are allowed.
-
-	You can specify IPv4/IPv6 address, IPv4/IPv6 network address in CIDR
-	format, and "any" or "none" keywords. The "!" prefix (for example
-	!192.0.2.33) means negation of the ACL element.
-
-	If not set, then zone inherits global allow-query from named.conf.
-
-* idnsAllowTransfer
-	Uses same format as idnsAllowQuery. Allows zone transfers for matching
-	clients.
-
-	If not set then zone inherits global allow-transfer from named.conf.
-
-* idnsAllowSyncPTR
-	Allow synchronization of A/AAAA records in zone with PTR records in reverse
-	zone. Reverse zone must have Dynamic update allowed. 
-	(See idnsAllowDynUpdate attribute and dyn_update configuration parameter.)
-
-* idnsForwardPolicy (default "first")
-	Specifies BIND9 zone forward policy. Proprietary value "none"
-	is equivalent to "forwarders {};" in BIND configuration,
-	i.e. effectively disables forwarding and ignores idnsForwarders
-	attribute.
-
-	Values "first" and "only" are relevant in conjunction with a valid
-	idnsForwarders attribute. Their meaning is same as in BIND9.
-
-* idnsForwarders
-	Defines multiple IP addresses to which recursive queries will be
-	forwarded. This is equivalent to "forwarders" statement in "master"
-	zone configuration.
-
-	I.e. local BIND replies authoritatively to queries when possible
-	(including authoritative NXDOMAIN answers) so forwarding affects only
-	queries made by BIND to answer recursive queries which cannot be
-	answered locally. Please see
-	https://lists.isc.org/pipermail/bind-users/2006-January/060810.html
-	https://lists.isc.org/pipermail/bind-users/2011-March/083244.html
-
-	It is multi-value attribute: Each IP address (and optional port) has to
-	be in own value. BIND9 syntax for "forwarders" is required.
-	Optional port can be specified by adding " port <number>" after IP 
-	address. IPv4 and IPv6 addresses are supported.
-	Examples: "1.2.3.4" or "1.2.3.4 port 553" or "A::B" or "A::B port 553"
-
-* idnsName
-	Absolute name of DNS zone. It is recommended to use names with trailing
-	period, e.g. "example.com."
-
-* idnsSecInlineSigning (default FALSE)
-	DNSSEC in-line signing configuration. Value TRUE is equivalent to
-	following zone configuration in named.conf (default BIND values):
-
-	auto-dnssec maintain;
-	sig-validity-interval 2592000; # 30 days
-	# re-sign interval will be 648000 seconds = 7.5 days
-	sig-signing-signatures 10;
-	sig-signing-nodes 10;
-	sig-signing-type 65534;
-	update-check-ksk yes;
-	dnssec-loadkeys-interval 60;   # minutes
-	key-directory "<plugin-instance-dir>/<zone-name>/keys";
-
-	There is no way to change those values at this moment.
-
-* idnsSOAserial
-	SOA serial number. It is automatically incremented after each change
-	in LDAP. External changes done by other LDAP clients are detected via
-	RFC 4533 (so-called syncrepl).
-
-	If serial number is lower than current UNIX timestamp, then
-	it is set to the timestamp value. If SOA serial is greater or equal
-	to current timestamp, then the serial is incremented by one.
-	(This is equivalent to BIND option 'serial-update-method unix'.)
-
-	In multi-master LDAP environments it is recommended to make
-	idnsSOAserial attribute non-replicated (locally significant).
-	It is recommended not to use multiple masters for single slave zone
-	if SOA serial is locally significant because serial numbers between
-	masters	aren't synchronized. It will cause problems with zone
-	transfers from multiple masters to single slave.
-
-* idnsZoneActive
-        Boolean which speicifies if particular DNS zone should be visible
-        to clients or not. This attribute can be changed at run-time.
-
-        Inactive zones are loaded into memory in the same way as active zones.
-        The only difference is that inactive zones are not added to DNS view
-        used by bind-dyndb-ldap.
-
-        Zone will be re-added to DNS view if idnsActiveZone attribute is
-        changed to TRUE so the change should be almost immediate.
-
-        Usual zone maintenance (serial number maintenance, DNSSEC in-line
-        signing etc.) is done for all zones, no matter if the zone
-        is active or not. This allows us to maintain zone journal so IXFR
-        works correctly even after zone re-activation.
-
-* nSEC3PARAMRecord
-	NSEC3PARAM resource record definition according to RFC5155.
-	Zone without NSEC3PARAM RR will use NSEC by default.
-
-
-4.2 Forward zone (idnsForwardZone)
-----------------------------------
-Object class idnsForwardZone is equivalent to type "forward" statement
-in named.conf.
-
-Attributes:
-* idnsForwarders
-	Defines multiple IP addresses to which all queries for sub-tree of DNS
-	will be forwarded. This is equivalent to "forwarders" statement in
-	"forward" zone configuration.
-
-	It is multi-value attribute: Each IP address (and optional port) has to
-	be in own value. BIND9 syntax for "forwarders" is required.
-	Optional port can be specified by adding " port <number>" after IP 
-	address. IPv4 and IPv6 addresses are supported.
-	Examples: "1.2.3.4" or "1.2.3.4 port 553" or "A::B" or "A::B port 553"
-
-* idnsForwardPolicy (default "first")
-	Specifies BIND9 zone forward policy. Proprietary value "none"
-	is equivalent to "forwarders {};" in BIND configuration,
-	i.e. effectively disables forwarding and ignores idnsForwarders
-	attribute.
-
-	Values "first" and "only" are relevant in conjunction with a valid
-	idnsForwarders attribute. Their meaning is same as in BIND9.
-
-* idnsName
-	Absolute name of DNS zone. It is recommended to use names with trailing
-	period, e.g. "example.com."
-
-Forward zones may conflict with automatic empty zones (defined in RFC 6303)
-because empty zones are authoritative and thus have higher priority
-than forwarding.
-Bind-dyndb-ldap will automatically unload empty zones which are super/sub
-domains of a forward zones if the forwarding policy is "only".
-A warning will be issued (and zone not unloaded) if the policy is "first"
-because this policy does not guarantee that queries will not leak to
-the public Internet.
-
-Unloaded empty zones will not be loaded back even if the forward zone is later
-deleted. The empty zones will be loaded on each BIND reload.
-
-
-4.3 Global configuration object (idnsConfigObject)
---------------------------------------------------
-Object class idnsConfigObject provides global configuration common
-for all zones.
-
-Attributes:
-* idnsAllowSyncPTR
-	Semantics is equivalent to "sync_ptr" option described in plugin's
-	config and to idnsAllowSyncPTR attribute in idnsZone.
-
-* idnsForwarders
-* idnsForwardPolicy
-	Semantics is equivalent to "forward" statement in named.conf.
-	Syntax is the same as in forward zone, please see previous section.
-
-
-4.4 Per-server configuration object (idnsServerConfigObject)
-------------------------------------------------------------
-Object class idnsConfigObject provides global configuration common
-for all zones. A plugin instance will read configuration
-only from entries with matching idnsServerId.
-
-Attributes:
-* idnsServerId
-	Configuration identifier (arbitrary string).
-	A plugin instance will use only objects whose idnsServerId value
-	matches server_id value in plugin's config.
-
-* idnsForwarders
-* idnsForwardPolicy
-	Same meaning as in global configuration object (idnsConfigObject).
-
-* idnsSOAmName
-	Equivalent to fake_mname option in plugin's config.
-
-* idnsSubstitutionVariable
-	This attribute associates string value with user-defined name.
-	These named variables can be used later in record template processing.
-	Variable name is specified as LDAP sub-type. (The attribute cannot be
-	used without sub-type. Exactly one instance of each sub-type
-	is required.)
-	For further information please see
-	https://fedorahosted.org/bind-dyndb-ldap/wiki/Design/RecordGenerator
-
-	LIMITATION: Current plugin version supports only "ipalocation" variable
-
-
-4.5 Record template (idnsTemplateObject)
-----------------------------------------
-Object class idnsTemplateObject provides facility for dynamic resource record
-generation. The template entry must contain idnsTemplateAttribute with
-string template.
-
-Optionally the same entry can contain statically defined resource records
-in *Record attributes. All statically defined record values are ignored
-when template is present and substitution into template is successful.
-The substitution is successful only if all variables used
-by the template string are defined.
-
-Attributes:
-* idnsTemplateAttribute
-	String subtitution template. All occurrences of \{variable_name\}
-	are replaced with respective strings from plugin configuration.
-	Remaining parts of the original string are just copied into the output.
-
-	Double-escaped strings \\{ \\} do not trigger substitution.
-	Nested references will expand only innermost variable: \{\{var1\}\}
-	Non-matching parentheses and other garbage will be copied verbatim
-	without triggering an error.
-
-	Resulting resource record type is specified as LDAP sub-type.
-	(The attribute cannot be used without sub-type.
-	Exactly one instance of each sub-type is required.)
-
-	Example - LDIF snippet:
-		idnsSubstitutionVariable;ipalocation: brno
-		idnsTemplateAttribute;CNAMERecord: server.\{substitutionvariable_ipalocation\}
-		will generate CNAME record: server.brno
-	For further information please see
-	https://fedorahosted.org/bind-dyndb-ldap/wiki/Design/RecordGenerator
-
-
-5. Configuration
-================
-
-To configure dynamic loading of back-end, you must put a "dynamic-db"
-clause into your named.conf. The clause must then be followed by a
-string denoting the name. The name is not that much important, it is
-passed to the plug-in and might be used for example, for logging
-purposes. Following after that is a set of options enclosed between
-curly brackets.
-
-The most important option here is "library". It names a shared object
-file that will be opened and loaded. The "arg" option specifies a string
-that is passed directly to the plugin. You can specify multiple "arg"
-options. The LDAP back-end follows the convention that the first word of
-this string is the name of the setting and the rest is the value.
-
-
-5.1 Configuration options
--------------------------
-List of configuration options follows:
-
-5.1.1 LDAP connection
----------------------
-uri
-	The Uniform Resource Identifier pointing to the LDAP server we
-	wish to connect to. This string is directly passed to the
-	ldap_initialize(3) function. This option is mandatory.
-	Example: ldap://ldap.example.com
-
-connections (default 2)
-	Number of connections the LDAP driver should try to establish to
-	the LDAP server. It's best if this matches the number of threads
-	BIND creates, for performance reasons. However, your LDAP server
-	configuration might only allow certain number of connections per
-	client.
-
-base
-	This is the search base that will be used by the LDAP back-end
-	to search for DNS zones. It is mandatory.
-
-auth_method (default "none")
-	The method used to authenticate to the LDAP server. Currently
-	supported methods are "none", "simple" and "sasl". The none
-	method is effectively a simple authentication without password.
-
-bind_dn (default "")
-	Distinguished Name used to bind to the LDAP server. If this is
-	empty and the auth_method is set to "simple", the LDAP back-end
-	will fall-back and use the "none" authentication method.
-
-password (default "")
-	Password for simple and SASL authentication. If the authentication
-	method is set to "simple" and the password is empty, the LDAP
-	driver will fall-back to the "none" authentication method.
-
-sasl_mech (default "GSSAPI")
-	Name of the SASL mechanism to be used for negotiation.
-
-sasl_auth_name
-	The user name to be used for SASL authentication.
-
-sasl_user
-	The user name to be used for SASL proxy authorization.
-
-sasl_password
-	The password to use for the SASL authentication.
-
-sasl_realm
-	The SASL realm name.
-
-krb5_keytab
-	Path to the kerberos keytab containing service credentials to be used
-	for SASL authentication. Append the "FILE:" prefix to the file path.
-	(FILE:/etc/named.keytab, for example)
-
-krb5_principal
-	Kerberos principal of the service, used for SASL authentication.
-	If not set then it is copied from "sasl_user" option. Principal
-	is loaded from file specified in "krb5_keytab" option.
-
-timeout (default 10)
-	Timeout (in seconds) of the queries to the LDAP server. If the LDAP
-	server don't respond before this timeout then lookup is aborted and
-	BIND returns SERVFAIL. Value "0" means infinite timeout (no timeout).
-
-reconnect_interval (default 60)
-	Time (in seconds) after that the plugin should try to connect to LDAP 
-	server again in case connection is lost and immediate reconnection 
-	fails.
-
-ldap_hostname (default "")
-	Sets hostname of the LDAP server. When it is set to "", actual
-	/bin/hostname is used. Please prefer "uri" option, this option should be
-	used only in special cases, for example when GSSAPI authentication
-	is used and named service has Kerberos principal different from
-	/bin/hostname output.
-
-
-5.1.2 Special DNS features
---------------------------
-fake_mname (default "")
-	Ignore value of the idnsSOAmName (primary master DNS name) attribute
-	and use this value instead. This allows multiple BIND processes to share
-	one LDAP database and every BIND reports itself as a primary master in
-	SOA record, for example.
-
-sync_ptr (default no)
-	Set this option to "yes" if you would like to keep PTR record 
-	synchronized with coresponding A/AAAA record for all zones.
-	If this option is set to "no", the LDAP driver will check
-	the idnsAllowSyncPTR attribute which specifies the synchronization
-	policy for PTR records in a zone. When an A/AAAA record is deleted 
-	the PTR record must point to the same hostname. 
-	
-dyn_update (default no)
-	Set this option to "yes" if you would like to allow dynamic zone updates.
-	This setting can be overridden for each zone individually
-	by idnsAllowDynUpdate attribute.
-
-
-5.1.3 Plumbing
---------------
-verbose_checks (default no)
-	Set this option to "yes" if you would like to log all failures
-	in internal CHECK() macros. This option is recommended only for
-	debugging purposes. It could produce huge amount of log messages
-	on a loaded system!
-
-directory (default is
-           "dyndb-ldap/<current instance name from dynamic-db directive>")
-	Specifies working directory for plug-in. The path has to be writeable
-	by named because plug-in will create sub-directory for each zone.
-	These sub-directories will contain temporary files like zone dump, zone
-	journal, zone keys etc.
-	The path is relative to "directory" specified in BIND options.
-	See section 6 (DNSSEC) for examples.
-
-5.2 Sample configuration
-------------------------
-Let's take a look at a sample configuration:
-
-options {
-	directory "/var/named/";
-};
-
-dynamic-db "my_db_name" {
-	library "ldap.so";
-	arg "uri ldap://ldap.example.com";
-	arg "base cn=dns, dc=example, dc=com";
-	arg "auth_method none";
-};
-
-With this configuration, the LDAP back-end will try to connect to server
-ldap.example.com with simple authentication, without any password. It
-will then use RFC 4533 refresh&persist search in the "cn=dns,dc=example,dc=com"
-base for entries with object class idnsZone and idnsRecord.
-For each idnsZone entry it will find, it will register a new zone with BIND.
-For each idnsRecord entry it will create domain name in particular zone.
-The LDAP back-end will keep each record it gets from LDAP in its memory.
-
-Working directory for the plug-in will be "/var/named/dyndb-ldap/my_db_name/",
-so hypothetical zone "example.com" will use sub-directory
-"/var/named/dyndb-ldap/my_db_name/master/example.com/".
-
-5.3 Configuration in LDAP
--------------------------
-Some options can be configured in LDAP as idnsConfigObject attributes.
-Value configured in LDAP has priority over value in configuration file.
-(This behavior will change in future versions!)
-
-Following options are supported (option = attribute equivalent):
-
-forwarders = idnsForwarders (BIND native option)
-forward = idnsForwardPolicy (BIND native option)
-sync_ptr = idnsAllowSyncPTR
-
-Forward policy option cannot be set without setting forwarders at the same time.
-
-
-6. DNSSEC support
-=================
-
-In-line signing support in this plugin allows to use this BIND feature
-for zones in LDAP.
-
-Signatures are automatically generated by plugin during zone loading
-and signatures are never written back to LDAP. DNSKEY, RRSIG, NSEC and NSEC3
-records in LDAP are ignored because they are automatically managed by BIND.
-
-NSEC3 can be enabled by writting NSEC3PARAM RR to particular zone object
-in LDAP.
-
-Dynamic updates made to in-line signed zones are written back to LDAP as usual
-and respective signatures are automatically re-generated as necessary.
-
-Key management has to be handled by user, i.e. user has to
-generate/delete keys and configure key timestamps as appropriate.
-
-Key directory for particular DNS zone is automatically configured to value:
-<plugin-instance-dir>/master/<zone-name>/keys
-
-<plugin-instance-dir> is described in section 5.1.3 of this file.
-<zone-name> is (transformed) textual representation of zone name without
-trailing period.
-
-Zone name will be automatically transformed before usage:
-- root zone is translated to '@' to prevent collision with filesystem '.'
-- digits, hyphen and underscore are left intact
-- letters of English alphabet are downcased
-- all other characters are escaped using %ASCII_HEX form, e.g. '/' => '%2F'
-- final dot is omited
-- labels are separated with '.'
-
-Example:
-* BIND directory: "/var/named"
-* bind-dyndb-ldap directory: "dyndb-ldap"
-* LDAP instance name: "ipa"
-* DNS zone: "example.com."
-* Resulting keys directory: "/var/named/dyndb-ldap/ipa/master/example.com/keys"
-
-* DNS zone: "TEST.0/1.a."
-* Resulting keys directory: "/var/named/dyndb-ldap/ipa/master/test.0%2F1.a/keys"
-
-Make sure that keys directory and files is readable by user used for BIND.
-
-
-7. License
-==========
-
-This package is licensed under the GNU General Public License, version 2
-only. See file COPYING for more information.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..de9cd1f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,591 @@
+1. Introduction
+===============
+The dynamic LDAP back-end is a plug-in for BIND that provides an LDAP
+database back-end capabilities. It requires dyndb interface which is present
+in BIND versions >= 9.11.0rc1.
+
+
+2. Features
+===========
+
+* support for dynamic updates
+* SASL authentication
+* SyncRepl (RFC 4533) for run-time synchronization with LDAP server
+* read-query performance nearly same as with plain BIND
+* AXFR and IXFR zone transfers are supported
+* DNSSEC in-line signing is supported, including dynamic updates
+
+
+3. Installation
+===============
+
+To install the LDAP back-end, extract the tarball and go to the unpacked
+directory. Then follow these steps:
+
+	$ ./configure --libdir=<libdir>
+	$ make
+
+Where `<libdir>` is a directory where your libdns is installed. This is
+typically going to be `/usr/lib` or `/usr/lib64` on 64 bit systems.
+
+If configure script complains that it `Can't obtain libdns version`,
+please verify you have installed bind development files (package bind9-dev
+or bind-devel) and you exported correct CPPFLAGS via
+
+	$ export CPPFLAGS=`isc-config.sh --cflags`
+
+Then, to install, run this as root:
+
+	$ make install
+
+This will install the file `ldap.so` into the `<libdir>/bind/` directory.
+
+Alternatively, the latest version can be obtained from Git repository.
+You can use following commands to prepare latest source tree for compilation:
+
+	$ git clone https://git.fedorahosted.org/git/bind-dyndb-ldap.git
+	$ cd bind-dyndb-ldap
+	$ autoreconf -fvi
+
+4. LDAP schema
+==============
+
+You can find the complete LDAP schema in the documentation directory. An
+example zone ldif is available in the doc directory.
+
+4.1 Master zone (idnsZone)
+--------------------------
+Object class `idnsZone` is equivalent to type `master` statement in `named.conf`.
+
+### Attributes
+* idnsAllowDynUpdate
+
+	Allow dynamic update of records in this zone. If attribute doesn't exist,
+	value `dyn_update` from plugin configuration will be used.
+
+* idnsAllowQuery
+
+	Specifies BIND9 zone ACL element as one string.
+
+	* Example 1: `idnsAllowQuery: 192.0.2.1;`
+	
+		In the first example above, only the client with 192.0.2.1
+		IP address is allowed to query records from the zone.
+
+	* Example 2: `idnsAllowQuery: !192.0.2.33; 192.0.2.0/24;`
+	
+		In the second example, queries from client 192.0.2.33
+		are refused but queries from all other clients in
+		the 192.0.2.0/24 network are allowed.
+
+	You can specify IPv4/IPv6 address, IPv4/IPv6 network address in CIDR
+	format, and `any` or `none` keywords. The `!` prefix (for example
+	`!192.0.2.33`) means negation of the ACL element.
+
+	If not set, then zone inherits global allow-query from named.conf.
+
+* idnsAllowTransfer
+
+	Uses same format as `idnsAllowQuery`. Allows zone transfers for matching
+	clients.
+
+	If not set then zone inherits global allow-transfer from named.conf.
+
+* idnsAllowSyncPTR
+
+	Allow synchronization of A/AAAA records in zone with PTR records in reverse
+	zone. Reverse zone must have Dynamic update allowed. 
+	(See `idnsAllowDynUpdate` attribute and `dyn_update` configuration parameter.)
+
+* idnsForwardPolicy (default `first`)
+
+	Specifies BIND9 zone forward policy. Proprietary value `none`
+	is equivalent to `forwarders {};` in BIND configuration,
+	i.e. effectively disables forwarding and ignores `idnsForwarders`
+	attribute.
+
+	Values `first` and `only` are relevant in conjunction with a valid
+	idnsForwarders attribute. Their meaning is same as in BIND9.
+
+* idnsForwarders
+
+	Defines multiple IP addresses to which recursive queries will be
+	forwarded. This is equivalent to `forwarders` statement in `master`
+	zone configuration.
+
+	I.e. local BIND replies authoritatively to queries when possible
+	(including authoritative NXDOMAIN answers) so forwarding affects only
+	queries made by BIND to answer recursive queries which cannot be
+	answered locally. Please see
+	https://lists.isc.org/pipermail/bind-users/2006-January/060810.html
+	https://lists.isc.org/pipermail/bind-users/2011-March/083244.html
+
+	It is multi-value attribute: Each IP address (and optional port) has to
+	be in own value. BIND9 syntax for `forwarders` is required.
+	Optional port can be specified by adding ` port <number>` after IP 
+	address. IPv4 and IPv6 addresses are supported.
+	Examples:
+	* `1.2.3.4`
+	* `1.2.3.4 port 553`
+	* `A::B`
+	* `A::B port 553`
+
+* idnsName
+
+	Absolute name of DNS zone. It is recommended to use names with trailing
+	period, e.g. `example.com.`
+
+* idnsSecInlineSigning (default `FALSE`)
+
+	DNSSEC in-line signing configuration. Value TRUE is equivalent to
+	following zone configuration in named.conf (default BIND values):
+
+		auto-dnssec maintain;
+		sig-validity-interval 2592000; # 30 days
+		# re-sign interval will be 648000 seconds = 7.5 days
+		sig-signing-signatures 10;
+		sig-signing-nodes 10;
+		sig-signing-type 65534;
+		update-check-ksk yes;
+		dnssec-loadkeys-interval 60;   # minutes
+		key-directory "<plugin-instance-dir>/<zone-name>/keys";
+
+	There is no way to change those values at this moment.
+
+* idnsSOAserial
+
+	SOA serial number. It is automatically incremented after each change
+	in LDAP. External changes done by other LDAP clients are detected via
+	RFC 4533 (so-called syncrepl).
+
+	If serial number is lower than current UNIX timestamp, then
+	it is set to the timestamp value. If SOA serial is greater or equal
+	to current timestamp, then the serial is incremented by one.
+	(This is equivalent to BIND option 'serial-update-method unix'.)
+
+	In multi-master LDAP environments it is recommended to make
+	idnsSOAserial attribute non-replicated (locally significant).
+	It is recommended not to use multiple masters for single slave zone
+	if SOA serial is locally significant because serial numbers between
+	masters	aren't synchronized. It will cause problems with zone
+	transfers from multiple masters to single slave.
+
+* idnsZoneActive
+
+	Boolean which speicifies if particular DNS zone should be visible
+	to clients or not. This attribute can be changed at run-time.
+
+	Inactive zones are loaded into memory in the same way as active zones.
+	The only difference is that inactive zones are not added to DNS view
+	used by bind-dyndb-ldap.
+
+	Zone will be re-added to DNS view if idnsActiveZone attribute is
+	changed to TRUE so the change should be almost immediate.
+
+	Usual zone maintenance (serial number maintenance, DNSSEC in-line
+	signing etc.) is done for all zones, no matter if the zone
+	is active or not. This allows us to maintain zone journal so IXFR
+	works correctly even after zone re-activation.
+
+* nSEC3PARAMRecord
+
+	NSEC3PARAM resource record definition according to RFC5155.
+	Zone without NSEC3PARAM RR will use NSEC by default.
+
+
+4.2 Forward zone (idnsForwardZone)
+----------------------------------
+Object class `idnsForwardZone` is equivalent to type `forward` statement
+in named.conf.
+
+### Attributes
+* idnsForwarders
+
+	Defines multiple IP addresses to which all queries for sub-tree of DNS
+	will be forwarded. This is equivalent to `forwarders` statement in
+	`forward` zone configuration.
+
+	It is multi-value attribute: Each IP address (and optional port) has to
+	be in own value. BIND9 syntax for `forwarders` is required.
+	Optional port can be specified by adding ` port <number>` after IP 
+	address. IPv4 and IPv6 addresses are supported.
+	Examples:
+	* `1.2.3.4`
+	* `1.2.3.4 port 553`
+	* `A::B`
+	* `A::B port 553`
+
+* idnsForwardPolicy (default `first`)
+
+	Specifies BIND9 zone forward policy. Proprietary value `none`
+	is equivalent to `forwarders {};` in BIND configuration,
+	i.e. effectively disables forwarding and ignores `idnsForwarders`
+	attribute.
+
+	Values `first` and `only` are relevant in conjunction with a valid
+	`idnsForwarders` attribute. Their meaning is same as in BIND9.
+
+* idnsName
+
+	Absolute name of DNS zone. It is recommended to use names with trailing
+	period, e.g. `example.com.`
+
+Forward zones may conflict with automatic empty zones (defined in RFC 6303)
+because empty zones are authoritative and thus have higher priority
+than forwarding.
+Bind-dyndb-ldap will automatically unload empty zones which are super/sub
+domains of a forward zones if the forwarding policy is `only`.
+A warning will be issued (and zone not unloaded) if the policy is `first`
+because this policy does not guarantee that queries will not leak to
+the public Internet.
+
+Unloaded empty zones will not be loaded back even if the forward zone is later
+deleted. The empty zones will be loaded on each BIND reload.
+
+
+4.3 Global configuration object (idnsConfigObject)
+--------------------------------------------------
+Object class idnsConfigObject provides global configuration common
+for all zones.
+
+### Attributes
+* idnsAllowSyncPTR
+
+	Semantics is equivalent to `sync_ptr` option described in plugin's
+	config and to `idnsAllowSyncPTR` attribute in `idnsZone`.
+
+* idnsForwarders
+* idnsForwardPolicy
+
+	Semantics is equivalent to `forward` statement in `named.conf`.
+	Syntax is the same as in forward zone, please see previous section.
+
+
+4.4 Per-server configuration object (idnsServerConfigObject)
+------------------------------------------------------------
+Object class idnsConfigObject provides global configuration common
+for all zones. A plugin instance will read configuration
+only from entries with matching idnsServerId.
+
+### Attributes
+* idnsServerId
+
+	Configuration identifier (arbitrary string).
+	A plugin instance will use only objects whose `idnsServerId` value
+	matches `server_id` value in plugin's config.
+
+* idnsForwarders
+* idnsForwardPolicy
+
+	Same meaning as in global configuration object (`idnsConfigObject`).
+
+* idnsSOAmName
+
+	Equivalent to `fake_mname` option in plugin's config.
+
+* idnsSubstitutionVariable
+
+	This attribute associates string value with user-defined name.
+	These named variables can be used later in record template processing.
+	Variable name is specified as LDAP sub-type. (The attribute cannot be
+	used without sub-type. Exactly one instance of each sub-type
+	is required.)
+	For further information please see
+	https://fedorahosted.org/bind-dyndb-ldap/wiki/Design/RecordGenerator
+
+	LIMITATION: Current plugin version supports only `ipalocation` variable
+
+
+4.5 Record template (idnsTemplateObject)
+----------------------------------------
+Object class idnsTemplateObject provides facility for dynamic resource record
+generation. The template entry must contain idnsTemplateAttribute with
+string template.
+
+Optionally the same entry can contain statically defined resource records
+in *Record attributes. All statically defined record values are ignored
+when template is present and substitution into template is successful.
+The substitution is successful only if all variables used
+by the template string are defined.
+
+### Attributes
+* idnsTemplateAttribute
+	String subtitution template. All occurrences of \{variable_name\}
+	are replaced with respective strings from plugin configuration.
+	Remaining parts of the original string are just copied into the output.
+
+	Double-escaped strings \\{ \\} do not trigger substitution.
+	Nested references will expand only innermost variable: \{\{var1\}\}
+	Non-matching parentheses and other garbage will be copied verbatim
+	without triggering an error.
+
+	Resulting resource record type is specified as LDAP sub-type.
+	(The attribute cannot be used without sub-type.
+	Exactly one instance of each sub-type is required.)
+
+	Example - LDIF snippet:
+	
+		idnsSubstitutionVariable;ipalocation: brno
+		idnsTemplateAttribute;CNAMERecord: server.\{substitutionvariable_ipalocation\}
+	will generate CNAME record: `server.brno`
+		
+	For further information please see
+	https://fedorahosted.org/bind-dyndb-ldap/wiki/Design/RecordGenerator
+
+
+5. Configuration
+================
+
+To configure dynamic loading of back-end, you must put a `dyndb`
+clause into your named.conf. The clause must then be followed by a
+string denoting the name of the instance and path to dyndb library.
+
+The name is not that much important, it is passed to the plug-in
+and is used for logging purposes and for naming working directories.
+
+Library path must point to a shared object file that will be opened and loaded.
+
+Name and library path have to be followed by set of options enclosed between
+curly brackets. Example:
+
+	dyndb "example-ldap" "/usr/lib64/bind/ldap.so" {
+		uri "ldap://ldap.example.com";
+		base "cn=dns, dc=example,dc=com";
+		auth_method "none";
+	};
+
+5.1 Configuration options
+-------------------------
+List of configuration options follows:
+
+5.1.1 LDAP connection
+---------------------
+* uri
+
+	The Uniform Resource Identifier pointing to the LDAP server we
+	wish to connect to. This string is directly passed to the
+	ldap_initialize(3) function. This option is mandatory.
+	Example: "ldap://ldap.example.com"
+
+* connections (default 2)
+
+	Number of connections the LDAP driver should try to establish to
+	the LDAP server. It's best if this matches the number of threads
+	BIND creates, for performance reasons. However, your LDAP server
+	configuration might only allow certain number of connections per
+	client.
+
+* base
+	This is the search base that will be used by the LDAP back-end
+	to search for DNS zones. This option is mandatory.
+	Example: "cn=dns, dc=example,dc=com";
+
+* auth_method (default "none")
+
+	The method used to authenticate to the LDAP server. Currently
+	supported methods are "none", "simple" and "sasl". The none
+	method is effectively a simple authentication without password.
+
+* bind_dn (default "")
+
+	Distinguished Name used to bind to the LDAP server. If this is
+	empty and the auth_method is set to "simple", the LDAP back-end
+	will fall-back and use the "none" authentication method.
+
+* password (default "")
+
+	Password for simple and SASL authentication. If the authentication
+	method is set to "simple" and the password is empty, the LDAP
+	driver will fall-back to the "none" authentication method.
+
+* sasl_mech (default "GSSAPI")
+
+	Name of the SASL mechanism to be used for negotiation.
+
+* sasl_auth_name
+
+	The user name to be used for SASL authentication.
+
+* sasl_user
+
+	The user name to be used for SASL proxy authorization.
+
+* sasl_password
+
+	The password to use for the SASL authentication.
+
+* sasl_realm
+
+	The SASL realm name.
+
+* krb5_keytab
+
+	Path to the kerberos keytab containing service credentials to be used
+	for SASL authentication. Append the "FILE:" prefix to the file path.
+	Example: "FILE:/etc/named.keytab"
+
+* krb5_principal
+
+	Kerberos principal of the service, used for SASL authentication.
+	If not set then it is copied from "sasl_user" option. Principal
+	is loaded from file specified in "krb5_keytab" option.
+
+* timeout (default 10)
+
+	Timeout (in seconds) of the queries to the LDAP server. If the LDAP
+	server don't respond before this timeout then lookup is aborted and
+	BIND returns SERVFAIL. Value "0" means infinite timeout (no timeout).
+
+* reconnect_interval (default 60)
+
+	Time (in seconds) after that the plugin should try to connect to LDAP 
+	server again in case connection is lost and immediate reconnection 
+	fails.
+
+* ldap_hostname (default "")
+
+	Sets hostname of the LDAP server. When it is set to "", actual
+	`/bin/hostname` is used. Please prefer `uri` option, this option should be
+	used only in special cases, for example when GSSAPI authentication
+	is used and named service has Kerberos principal different from
+	`/bin/hostname` output.
+
+
+5.1.2 Special DNS features
+--------------------------
+* fake_mname
+
+	Ignore value of the idnsSOAmName (primary master DNS name) attribute
+	and use this value instead. This allows multiple BIND processes to share
+	one LDAP database and every BIND reports itself as a primary master in
+	SOA record, for example.
+
+* sync_ptr (default no)
+
+	Set this option to `yes` if you would like to keep PTR record 
+	synchronized with coresponding A/AAAA record for all zones.
+	If this option is set to `no`, the LDAP driver will check
+	the idnsAllowSyncPTR attribute which specifies the synchronization
+	policy for PTR records in a zone. When an A/AAAA record is deleted 
+	the PTR record must point to the same hostname. 
+	
+* dyn_update (default no)
+
+	Set this option to `yes` if you would like to allow dynamic zone updates.
+	This setting can be overridden for each zone individually
+	by idnsAllowDynUpdate attribute.
+
+
+5.1.3 Plumbing
+--------------
+* verbose_checks (default no)
+
+	Set this option to `yes` if you would like to log all failures
+	in internal CHECK() macros. This option is recommended only for
+	debugging purposes. It could produce huge amount of log messages
+	on a loaded system!
+
+* directory (default is
+             `dyndb-ldap/<current instance name from dynamic-db directive>`)
+        
+	Specifies working directory for plug-in. The path has to be writeable
+	by named because plug-in will create sub-directory for each zone.
+	These sub-directories will contain temporary files like zone dump, zone
+	journal, zone keys etc.
+	The path is relative to `directory` specified in BIND options.
+	See section 6 (DNSSEC) for examples.
+
+5.2 Sample configuration
+------------------------
+Let's take a look at a sample configuration:
+
+	options {
+		directory "/var/named/";
+	};
+	
+	dyndb "my_db_name" "/usr/lib64/bind/ldap.so" {
+		uri "ldap://ldap.example.com";
+		base "cn=dns, dc=example,dc=com";
+		auth_method "none";
+	};
+
+With this configuration, the LDAP back-end will try to connect to server
+ldap.example.com with simple authentication, without any password. It
+will then use RFC 4533 refresh&persist search in the `cn=dns,dc=example,dc=com`
+base for entries with object class `idnsZone` and `idnsRecord`.
+For each idnsZone entry it will find, it will register a new zone with BIND.
+For each idnsRecord entry it will create domain name in particular zone.
+The LDAP back-end will keep each record it gets from LDAP in its memory.
+
+Working directory for the plug-in will be `/var/named/dyndb-ldap/my_db_name/`,
+so hypothetical zone `example.com` will use sub-directory
+`/var/named/dyndb-ldap/my_db_name/master/example.com/`.
+
+5.3 Configuration in LDAP
+-------------------------
+Some options can be configured in LDAP as `idnsConfigObject` attributes.
+Value configured in LDAP has priority over value in configuration file.
+(This behavior will change in future versions!)
+
+Following options are supported (option = attribute equivalent):
+option     | LDAP attribute
+-----------| --------------
+forwarders | idnsForwarders (BIND native option)
+forward    | idnsForwardPolicy (BIND native option)
+sync_ptr   | idnsAllowSyncPTR
+
+Forward policy option cannot be set without setting forwarders at the same time.
+
+
+6. DNSSEC support
+=================
+
+In-line signing support in this plugin allows to use this BIND feature
+for zones in LDAP.
+
+Signatures are automatically generated by plugin during zone loading
+and signatures are never written back to LDAP. DNSKEY, RRSIG, NSEC and NSEC3
+records in LDAP are ignored because they are automatically managed by BIND.
+
+NSEC3 can be enabled by writting NSEC3PARAM RR to particular zone object
+in LDAP.
+
+Dynamic updates made to in-line signed zones are written back to LDAP as usual
+and respective signatures are automatically re-generated as necessary.
+
+Key management has to be handled by user, i.e. user has to
+generate/delete keys and configure key timestamps as appropriate.
+
+Key directory for particular DNS zone is automatically configured to value:
+	<plugin-instance-dir>/master/<zone-name>/keys
+
+`<plugin-instance-dir>` is described in section 5.1.3 of this file.
+`<zone-name>` is (transformed) textual representation of zone name without
+trailing period.
+
+Zone name will be automatically transformed before usage:
+- root zone is translated to `@` to prevent collision with filesystem `.`
+- digits, hyphen and underscore are left intact
+- letters of English alphabet are downcased
+- all other characters are escaped using %ASCII_HEX form, e.g. `/` => `%2F`
+- final dot is omited
+- labels are separated with `.`
+
+Example:
+* BIND directory: `/var/named`
+* bind-dyndb-ldap directory: `dyndb-ldap`
+* LDAP instance name: `ipa`
+* DNS zone: `example.com.`
+* Resulting keys directory: `/var/named/dyndb-ldap/ipa/master/example.com/keys`
+
+* DNS zone: `TEST.0/1.a.`
+* Resulting keys directory: `/var/named/dyndb-ldap/ipa/master/test.0%2F1.a/keys`
+
+Make sure that keys directory and files is readable by user used for BIND.
+
+
+7. License
+==========
+
+This package is licensed under the GNU General Public License, version 2
+only. See file COPYING for more information.
diff --git a/configure.ac b/configure.ac
index 9b26058..50e41f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
 AC_PREREQ([2.59])
-AC_INIT([bind-dyndb-ldap], [10.1], [freeipa-devel@redhat.com])
+AC_INIT([bind-dyndb-ldap], [11.0], [freeipa-devel@redhat.com])
 
 AM_INIT_AUTOMAKE([-Wall foreign dist-bzip2])
 
-AC_CONFIG_SRCDIR([src/zone_manager.h])
+AC_CONFIG_SRCDIR([src/ldap_driver.c])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 
@@ -105,18 +105,18 @@ int main(void) {
 [AC_MSG_ERROR([Cross compiling is not supported.])]
 )
 
-dnl isc__errno2result() is typically not present in standard header files
-AC_MSG_CHECKING([isc__errno2result availability in header files])
+dnl isc_errno_toresult() was not available in older header files
+AC_MSG_CHECKING([isc_errno_toresult availability])
 AC_TRY_RUN([
-#include <isc/errno2result.h>
+#include <isc/errno.h>
 int main(void) {
-	isc__errno2result(0);
+	isc_errno_toresult(0);
 	return 0;
 }],
 [AC_MSG_RESULT([yes])],
 [AC_MSG_ERROR([
- Can't find isc__errno2result() or header isc/errno2result.h:
- Please install bind-lite-devel package or similar.])],
+ Can't find isc_errno_toresult() or header isc/errno.h:
+ Please install bind-devel package or similar.])],
 [AC_MSG_ERROR([Cross compiling is not supported.])]
 )
 
diff --git a/doc/schema.ldif b/doc/schema.ldif
index 8fdc99f..77c5b0e 100644
--- a/doc/schema.ldif
+++ b/doc/schema.ldif
@@ -362,9 +362,16 @@ attributeTypes: ( 2.16.840.1.113730.3.8.5.31
  NAME 'idnsServerId'
  DESC 'DNS server identifier'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
- EQUALITY caseIgnoreMatch
+ EQUALITY caseIgnoreMatch 
  SINGLE-VALUE )
 #
+attributeTypes: ( 2.16.840.1.113730.3.8.5.29 
+ NAME 'idnsTemplateAttribute' 
+ DESC 'Template attribute for dynamic attribute generation' 
+ EQUALITY caseIgnoreIA5Match 
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 
+ X-ORIGIN 'IPA v4.4' )
+#
 attributeTypes: ( 2.16.840.1.113730.3.8.5.30 
  NAME 'idnsSubstitutionVariable' 
  DESC 'User defined variable for DNS plugin' 
@@ -426,6 +433,6 @@ objectClasses: ( 2.16.840.1.113730.3.8.6.6
 objectClasses: ( 2.16.840.1.113730.3.8.6.5 
  NAME 'idnsTemplateObject' 
  DESC 'Template object for dynamic DNS attribute generation' 
- SUP top
+ SUP top 
  AUXILIARY 
  MUST ( idnsTemplateAttribute ) )
diff --git a/src/Makefile.am b/src/Makefile.am
index 238d8ef..e1e3968 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,7 +4,6 @@ bindplugindir=$(libdir)/bind
 HDRS =				\
 	acl.h			\
 	bindcfg.h		\
-	compat.h		\
 	empty_zones.h		\
 	fs.h			\
 	fwd.h			\
@@ -27,7 +26,6 @@ HDRS =				\
 	types.h			\
 	util.h			\
 	zone.h			\
-	zone_manager.h		\
 	zone_register.h
 
 ldap_la_SOURCES =		\
@@ -54,7 +52,6 @@ ldap_la_SOURCES =		\
 	syncrepl.c		\
 	str.c			\
 	zone.c			\
-	zone_manager.c		\
 	zone_register.c
 
 ldap_la_CFLAGS = -Wall -Wextra @WERROR@ -std=gnu99 -O2
diff --git a/src/compat.h b/src/compat.h
deleted file mode 100644
index 00e3da5..0000000
--- a/src/compat.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009  bind-dyndb-ldap authors; see COPYING for license
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#else
-#error "Can't compile without config.h"
-#endif
-
-/*
- * dns_rdatalist_fromrdataset() did not exist in older versions of libdns.
- * Add a substitude function here.
- */
-#if LIBDNS_VERSION_MAJOR < 40
-static inline isc_result_t
-dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset,
-			   dns_rdatalist_t **rdatalist)
-{
-	REQUIRE(rdatalist != NULL && rdataset != NULL);
-
-	*rdatalist = rdataset->private1;
-
-	return ISC_R_SUCCESS;
-}
-#endif /* LIBDNS_VERSION_MAJOR < 40 */
-
-/*
- * In older libdns versions, isc_refcount_init() was defined as a macro.
- * However, in newer versions, it is a function returning isc_result_t type.
- * This piece of code should take care of that problem.
- */
-#if LIBDNS_VERSION_MAJOR < 30
-#include <isc/refcount.h>
-
-static inline isc_result_t
-isc_refcount_init_func(isc_refcount_t *ref, unsigned int n)
-{
-	isc_refcount_init(ref, n);
-	return ISC_R_SUCCESS;
-}
-#undef isc_refcount_init
-#define isc_refcount_init isc_refcount_init_func
-#endif /* LIBDNS_VERSION_MAJOR < 30 */
diff --git a/src/fs.c b/src/fs.c
index 09b71d7..61c46b5 100644
--- a/src/fs.c
+++ b/src/fs.c
@@ -10,7 +10,7 @@
 
 #include <isc/dir.h>
 #include <isc/file.h>
-#include <isc/errno2result.h>
+#include <isc/errno.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -37,7 +37,7 @@ fs_dir_create(const char *dir_name)
 	if (ret == 0)
 		result = ISC_R_SUCCESS;
 	else
-		result = isc__errno2result(errno);
+		result = isc_errno_toresult(errno);
 
 	if (result != ISC_R_SUCCESS && result != ISC_R_FILEEXISTS) {
 		log_error_r("unable to create directory '%s', working directory "
@@ -50,7 +50,7 @@ fs_dir_create(const char *dir_name)
 		 * solely for this purpose. */
 		ret = chmod(dir_name, dir_mode);
 		if (ret != 0) {
-			result = isc__errno2result(errno);
+			result = isc_errno_toresult(errno);
 			log_error_r("unable to chmod directory '%s', "
 				    "working directory is '%s'",
 				    dir_name, dir_curr);
diff --git a/src/fwd.c b/src/fwd.c
index 1f6a9e5..840f0e8 100644
--- a/src/fwd.c
+++ b/src/fwd.c
@@ -69,11 +69,7 @@ fwd_list_len(dns_forwarders_t *fwdrs) {
 
 	REQUIRE(fwdrs != NULL);
 
-#if LIBDNS_VERSION_MAJOR < 140
-	for (isc_sockaddr_t *fwdr = ISC_LIST_HEAD(fwdrs->addrs);
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	for (dns_forwarder_t *fwdr = ISC_LIST_HEAD(fwdrs->fwdrs);
-#endif
 	     fwdr != NULL;
 	     fwdr = ISC_LIST_NEXT(fwdr, link)) {
 		len++;
@@ -169,11 +165,7 @@ fwd_print_list_buff(isc_mem_t *mctx, dns_forwarders_t *fwdrs,
 	const cfg_obj_t *faddresses;
 	const cfg_listelt_t *fwdr_cfg; /* config representation */
 	/* internal representation */
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddr_t *fwdr_int;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	dns_forwarder_t *fwdr_int;
-#endif
 
 	isc_buffer_initnull(&tmp_buf);
 	tmp_buf.mctx = mctx;
@@ -197,20 +189,12 @@ fwd_print_list_buff(isc_mem_t *mctx, dns_forwarders_t *fwdrs,
 	 * data from the internal one to cfg data structures.*/
 	faddresses = cfg_tuple_get(forwarders_cfg, "addresses");
 	for (fwdr_int = ISC_LIST_HEAD(
-#if LIBDNS_VERSION_MAJOR < 140
-			fwdrs->addrs
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 			fwdrs->fwdrs
-#endif
 			), fwdr_cfg = cfg_list_first(faddresses);
 	     INSIST((fwdr_int == NULL) == (fwdr_cfg == NULL)), fwdr_int != NULL;
 	     fwdr_int = ISC_LIST_NEXT(fwdr_int, link), fwdr_cfg = cfg_list_next(fwdr_cfg)) {
-#if LIBDNS_VERSION_MAJOR < 140
-		fwdr_cfg->obj->value.sockaddr = *fwdr_int;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 		fwdr_cfg->obj->value.sockaddrdscp.sockaddr = fwdr_int->addr;
 		fwdr_cfg->obj->value.sockaddrdscp.dscp = fwdr_int->dscp;
-#endif
 	}
 	cfg_print(faddresses, buffer_append_str, &tmp_buf);
 
@@ -259,12 +243,7 @@ cleanup:
 
 static isc_result_t
 fwd_parse_str(const char *fwdrs_str, isc_mem_t *mctx,
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddrlist_t *fwdrs
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
-	dns_forwarderlist_t *fwdrs
-#endif
-	)
+	      dns_forwarderlist_t *fwdrs)
 {
 	isc_result_t result = ISC_R_SUCCESS;
 	cfg_parser_t *parser = NULL;
@@ -274,11 +253,7 @@ fwd_parse_str(const char *fwdrs_str, isc_mem_t *mctx,
 	const cfg_listelt_t *listel;
 	const cfg_obj_t *fwdr_cfg;
 	isc_sockaddr_t addr;
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddr_t *fwdr;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	dns_forwarder_t *fwdr;
-#endif
 
 	in_port_t port = 53;
 
@@ -301,12 +276,8 @@ fwd_parse_str(const char *fwdrs_str, isc_mem_t *mctx,
 		if (isc_sockaddr_getport(&addr) == 0)
 			isc_sockaddr_setport(&addr, port);
 		CHECKED_MEM_GET_PTR(mctx, fwdr);
-#if LIBDNS_VERSION_MAJOR < 140
-		*fwdr = addr;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 		fwdr->addr = addr;
 		fwdr->dscp = cfg_obj_getdscp(fwdr_cfg);
-#endif
 		ISC_LINK_INIT(fwdr, link);
 		ISC_LIST_APPEND(*fwdrs, fwdr, link);
 	}
@@ -320,18 +291,8 @@ cleanup:
 }
 
 static void
-fwdr_list_free(isc_mem_t *mctx,
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddrlist_t *fwdrs
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
-	dns_forwarderlist_t *fwdrs
-#endif
-	) {
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddr_t *fwdr;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
+fwdr_list_free(isc_mem_t *mctx, dns_forwarderlist_t *fwdrs) {
 	dns_forwarder_t *fwdr;
-#endif
 	while (!ISC_LIST_EMPTY(*fwdrs)) {
 		fwdr = ISC_LIST_HEAD(*fwdrs);
 		ISC_LIST_UNLINK(*fwdrs, fwdr, link);
@@ -357,11 +318,7 @@ fwd_setting_isexplicit(isc_mem_t *mctx, const settings_set_t *set,
 	isc_result_t result;
 	setting_t *setting = NULL;
 	dns_fwdpolicy_t	fwdpolicy;
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddrlist_t fwdrs;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	dns_forwarderlist_t fwdrs;
-#endif
 
 	REQUIRE(isexplicit != NULL);
 	ISC_LIST_INIT(fwdrs);
@@ -440,11 +397,7 @@ fwd_parse_ldap(ldap_entry_t *entry, settings_set_t *set) {
 	ldap_valuelist_t values;
 	ldap_value_t *value;
 	isc_buffer_t *tmp_buf = NULL; /* hack: only the base buffer is allocated */
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddrlist_t fwdrs;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	dns_forwarderlist_t fwdrs;
-#endif
 	const char *setting_str = NULL;
 
 	/**
@@ -547,11 +500,7 @@ fwd_configure_zone(const settings_set_t *set, ldap_instance_t *inst,
 	isc_mem_t *mctx = NULL;
 	dns_view_t *view = NULL;
 	isc_result_t lock_state = ISC_R_IGNORE;
-#if LIBDNS_VERSION_MAJOR < 140
-	isc_sockaddrlist_t fwdrs;
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 	dns_forwarderlist_t fwdrs;
-#endif
 	isc_boolean_t is_global_config;
 	dns_fixedname_t foundname;
 	const char *msg_use_global_fwds;
@@ -630,13 +579,8 @@ fwd_configure_zone(const settings_set_t *set, ldap_instance_t *inst,
 	run_exclusive_enter(inst, &lock_state);
 	CHECK(fwd_delete_table(view, name, msg_obj_type, set->name));
 	if (isconfigured == ISC_TRUE) {
-#if LIBDNS_VERSION_MAJOR < 140
-		CHECK(dns_fwdtable_add(view->fwdtable, name, &fwdrs,
-				       fwdpolicy));
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 		CHECK(dns_fwdtable_addfwd(view->fwdtable, name, &fwdrs,
 					  fwdpolicy));
-#endif
 	}
 	dns_view_flushcache(view);
 	run_exclusive_exit(inst, lock_state);
diff --git a/src/ldap_driver.c b/src/ldap_driver.c
index 83ec00a..b1b7336 100644
--- a/src/ldap_driver.c
+++ b/src/ldap_driver.c
@@ -9,13 +9,17 @@
 #endif
 
 #include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/hash.h>
+#include <isc/lib.h>
 #include <isc/mem.h>
+#include <isc/once.h>
 #include <isc/refcount.h>
 #include <isc/util.h>
 
 #include <dns/db.h>
 #include <dns/diff.h>
-#include <dns/dynamic_db.h>
+#include <dns/dyndb.h>
 #include <dns/dbiterator.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -29,13 +33,12 @@
 
 #include <string.h> /* For memcpy */
 
-#include "compat.h"
+#include "bindcfg.h"
 #include "ldap_driver.h"
 #include "ldap_helper.h"
 #include "ldap_convert.h"
 #include "log.h"
 #include "util.h"
-#include "zone_manager.h"
 #include "zone_register.h"
 
 #ifdef HAVE_VISIBILITY
@@ -181,18 +184,9 @@ detach(dns_db_t **dbp)
 
 /* !!! This could be required for optimizations (like on-disk cache). */
 static isc_result_t
-#if LIBDNS_VERSION_MAJOR < 140
-beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp)
-{
-
-	UNUSED(db);
-	UNUSED(addp);
-	UNUSED(dbloadp);
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
 	UNUSED(db);
 	UNUSED(callbacks);
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
 
 	fatal_error("ldapdb: method beginload() should never be called");
 
@@ -207,17 +201,9 @@ beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
 
 /* !!! This could be required for optimizations (like on-disk cache). */
 static isc_result_t
-#if LIBDNS_VERSION_MAJOR < 140
-endload(dns_db_t *db, dns_dbload_t **dbloadp)
-{
-
-	UNUSED(db);
-	UNUSED(dbloadp);
-#else /* LIBDNS_VERSION_MAJOR >= 140 */
 endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
 	UNUSED(db);
 	UNUSED(callbacks);
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
 
 	fatal_error("ldapdb: method endload() should never be called");
 
@@ -225,7 +211,6 @@ endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
 	return ISC_R_SUCCESS;
 }
 
-#if LIBDNS_VERSION_MAJOR >= 140
 static isc_result_t
 serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file)
 {
@@ -235,23 +220,17 @@ serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file)
 
 	return dns_db_serialize(ldapdb->rbtdb, version, file);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
 
 /* !!! This could be required for optimizations (like on-disk cache). */
 static isc_result_t
-dump(dns_db_t *db, dns_dbversion_t *version, const char *filename
-#if LIBDNS_VERSION_MAJOR >= 31
-     , dns_masterformat_t masterformat
-#endif
-     )
+dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+     dns_masterformat_t masterformat)
 {
 
 	UNUSED(db);
 	UNUSED(version);
 	UNUSED(filename);
-#if LIBDNS_VERSION_MAJOR >= 31
 	UNUSED(masterformat);
-#endif
 
 	fatal_error("ldapdb: method dump() should never be called");
 
@@ -422,22 +401,14 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out)
 }
 
 static isc_result_t
-createiterator(dns_db_t *db,
-#if LIBDNS_VERSION_MAJOR >= 50
-	       unsigned int options,
-#else
-	       isc_boolean_t relative_names,
-#endif
+createiterator(dns_db_t *db,  unsigned int options,
 	       dns_dbiterator_t **iteratorp)
 {
 	ldapdb_t *ldapdb = (ldapdb_t *) db;
 
 	REQUIRE(VALID_LDAPDB(ldapdb));
-#if LIBDNS_VERSION_MAJOR >= 50
+
 	return dns_db_createiterator(ldapdb->rbtdb, options, iteratorp);
-#else
-	return dns_db_createiterator(ldapdb->rbtdb, relative_names, iteratorp);
-#endif
 }
 
 static isc_result_t
@@ -675,7 +646,6 @@ settask(dns_db_t *db, isc_task_t *task)
 	dns_db_settask(ldapdb->rbtdb, task);
 }
 
-#if LIBDNS_VERSION_MAJOR >= 31
 static isc_result_t
 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep)
 {
@@ -685,9 +655,7 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep)
 
 	return dns_db_getoriginnode(ldapdb->rbtdb, nodep);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 31 */
 
-#if LIBDNS_VERSION_MAJOR >= 45
 static void
 transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp)
 {
@@ -698,9 +666,7 @@ transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp)
 	dns_db_transfernode(ldapdb->rbtdb, sourcep, targetp);
 
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 45 */
 
-#if LIBDNS_VERSION_MAJOR >= 50
 static isc_result_t
 getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
 			  dns_hash_t *hash, isc_uint8_t *flags,
@@ -767,9 +733,7 @@ isdnssec(dns_db_t *db)
 
 	return dns_db_isdnssec(ldapdb->rbtdb);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 50 */
 
-#if LIBDNS_VERSION_MAJOR >= 45
 static dns_stats_t *
 getrrsetstats(dns_db_t *db) {
 	ldapdb_t *ldapdb = (ldapdb_t *) db;
@@ -779,35 +743,7 @@ getrrsetstats(dns_db_t *db) {
 	return dns_db_getrrsetstats(ldapdb->rbtdb);
 
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 45 */
 
-#if LIBDNS_VERSION_MAJOR >= 82 && LIBDNS_VERSION_MAJOR < 140
-static isc_result_t
-rpz_enabled(dns_db_t *db, dns_rpz_st_t *st)
-{
-	ldapdb_t *ldapdb = (ldapdb_t *) db;
-
-	REQUIRE(VALID_LDAPDB(ldapdb));
-
-	return dns_db_rpz_enabled(ldapdb->rbtdb, st);
-}
-
-static void
-rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
-		   dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
-		   dns_rdataset_t *ardataset, dns_rpz_st_t *st,
-		   dns_name_t *query_qname)
-{
-	ldapdb_t *ldapdb = (ldapdb_t *) db;
-
-	REQUIRE(VALID_LDAPDB(ldapdb));
-
-	dns_db_rpz_findips(rpz, rpz_type, zone, ldapdb->rbtdb, version,
-			   ardataset, st, query_qname);
-}
-#endif /* LIBDNS_VERSION_MAJOR >= 82 && LIBDNS_VERSION_MAJOR < 140 */
-
-#if LIBDNS_VERSION_MAJOR >= 140
 void
 rpz_attach(dns_db_t *db, dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num)
 {
@@ -827,9 +763,7 @@ rpz_ready(dns_db_t *db)
 
 	return dns_db_rpz_ready(ldapdb->rbtdb);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
 
-#if LIBDNS_VERSION_MAJOR >= 90
 static isc_result_t
 findnodeext(dns_db_t *db, dns_name_t *name,
 		   isc_boolean_t create, dns_clientinfomethods_t *methods,
@@ -858,9 +792,7 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
 			      nodep, foundname, methods, clientinfo, rdataset,
 			      sigrdataset);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 90 */
 
-#if LIBDNS_VERSION_MAJOR >= 140
 isc_result_t
 setcachestats(dns_db_t *db, isc_stats_t *stats)
 {
@@ -871,11 +803,7 @@ setcachestats(dns_db_t *db, isc_stats_t *stats)
 	return dns_db_setcachestats(ldapdb->rbtdb, stats);
 }
 
-#if LIBDNS_VERSION_MAJOR >= 164
 size_t
-#else
-unsigned int
-#endif /* LIBDNS_VERSION_MAJOR >= 164 */
 hashsize(dns_db_t *db)
 {
 	ldapdb_t *ldapdb = (ldapdb_t *) db;
@@ -884,16 +812,23 @@ hashsize(dns_db_t *db)
 
 	return dns_db_hashsize(ldapdb->rbtdb);
 }
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
+
+isc_result_t
+nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name)
+{
+	ldapdb_t *ldapdb = (ldapdb_t *) db;
+
+	REQUIRE(VALID_LDAPDB(ldapdb));
+
+	return dns_db_nodefullname(ldapdb->rbtdb, node, name);
+}
 
 static dns_dbmethods_t ldapdb_methods = {
 	attach,
 	detach,
 	beginload,
 	endload,
-#if LIBDNS_VERSION_MAJOR >= 140
 	serialize, /* see dns_db_serialize(), implementation is not mandatory */
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
 	dump,
 	currentversion,
 	newversion,
@@ -917,37 +852,22 @@ static dns_dbmethods_t ldapdb_methods = {
 	ispersistent,
 	overmem,
 	settask,
-#if LIBDNS_VERSION_MAJOR >= 31
 	getoriginnode,
-#endif /* LIBDNS_VERSION_MAJOR >= 31 */
-#if LIBDNS_VERSION_MAJOR >= 45
 	transfernode,
-#if LIBDNS_VERSION_MAJOR >= 50
 	getnsec3parameters,
 	findnsec3node,
 	setsigningtime,
 	getsigningtime,
 	resigned,
 	isdnssec,
-#endif /* LIBDNS_VERSION_MAJOR >= 50 */
 	getrrsetstats,
-#endif /* LIBDNS_VERSION_MAJOR >= 45 */
-#if LIBDNS_VERSION_MAJOR >= 82 && LIBDNS_VERSION_MAJOR < 140
-	rpz_enabled,
-	rpz_findips,
-#endif /* LIBDNS_VERSION_MAJOR >= 82 && LIBDNS_VERSION_MAJOR < 140 */
-#if LIBDNS_VERSION_MAJOR >= 140
 	rpz_attach,
 	rpz_ready,
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
-#if LIBDNS_VERSION_MAJOR >= 90
 	findnodeext,
 	findext,
-#endif /* LIBDNS_VERSION_MAJOR >= 90 */
-#if LIBDNS_VERSION_MAJOR >= 140
 	setcachestats,
-	hashsize
-#endif /* LIBDNS_VERSION_MAJOR >= 140 */
+	hashsize,
+	nodefullname
 };
 
 isc_result_t ATTR_NONNULLS
@@ -1002,18 +922,17 @@ ldapdb_associate(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type,
 		 void *driverarg, dns_db_t **dbp) {
 
 	isc_result_t result;
-	ldap_instance_t *ldap_inst = NULL;
+	ldap_instance_t *ldap_inst = driverarg;
 	zone_register_t *zr = NULL;
 
-	UNUSED(driverarg); /* Currently we don't need any data */
-
 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
-	REQUIRE(argc == LDAP_DB_ARGC);
 	REQUIRE(type == LDAP_DB_TYPE);
 	REQUIRE(rdclass == LDAP_DB_RDATACLASS);
+	REQUIRE(argc == 0);
+	UNUSED(argv);
+	REQUIRE(driverarg != NULL);
 	REQUIRE(dbp != NULL && *dbp == NULL);
 
-	CHECK(manager_get_ldap_instance(argv[0], &ldap_inst));
 	zr = ldap_instance_getzr(ldap_inst);
 	if (zr == NULL)
 		CLEANUP_WITH(ISC_R_NOTFOUND);
@@ -1026,19 +945,16 @@ cleanup:
 
 isc_result_t
 ldapdb_create(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type,
-	      dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
-	      void *driverarg, dns_db_t **dbp)
+	      dns_rdataclass_t rdclass, void *driverarg, dns_db_t **dbp)
 {
 	ldapdb_t *ldapdb = NULL;
 	isc_result_t result;
 	isc_boolean_t lock_ready = ISC_FALSE;
 
-	UNUSED(driverarg); /* Currently we don't need any data */
-
 	/* Database instance name. */
-	REQUIRE(argc == LDAP_DB_ARGC);
 	REQUIRE(type == LDAP_DB_TYPE);
 	REQUIRE(rdclass == LDAP_DB_RDATACLASS);
+	REQUIRE(driverarg != NULL);
 	REQUIRE(dbp != NULL && *dbp == NULL);
 
 	CHECKED_MEM_GET_PTR(mctx, ldapdb);
@@ -1060,7 +976,7 @@ ldapdb_create(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type,
 	CHECK(dns_name_dupwithoffsets(name, mctx, &ldapdb->common.origin));
 
 	CHECK(isc_refcount_init(&ldapdb->refs, 1));
-	CHECK(manager_get_ldap_instance(argv[0], &ldapdb->ldap_inst));
+	ldapdb->ldap_inst = driverarg;
 
 	CHECK(dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
 			    dns_rdataclass_in, 0, NULL, &ldapdb->rbtdb));
@@ -1084,50 +1000,91 @@ cleanup:
 	return result;
 }
 
-static dns_dbimplementation_t *ldapdb_imp;
-const char *ldapdb_impname = "dynamic-ldap";
+static void
+library_init(void)
+{
+       log_info("bind-dyndb-ldap version " VERSION
+                " compiled at " __TIME__ " " __DATE__
+                ", compiler " __VERSION__);
+       cfg_init_types();
+}
+
+/*
+ * Driver version is called when loading the driver to ensure there
+ * is no API mismatch betwen the driver and the caller.
+ */
+VISIBLE int
+dyndb_version(unsigned int *flags) {
+	UNUSED(flags);
 
+	return (DNS_DYNDB_VERSION);
+}
 
+/*
+ * Driver init is called for each dyndb section in named.conf
+ * once during startup and then again on every reload.
+ *
+ * @code
+ * dyndb example-name "sample.so" { param1 param2 };
+ * @endcode
+ *
+ * @param[in] name        User-defined string from dyndb "name" {}; definition
+ *                        in named.conf.
+ *                        The example above will have name = "example-name".
+ * @param[in] parameters  User-defined parameters from dyndb section as one
+ *                        string. The example above will have
+ *                        params = "param1 param2";
+ * @param[out] instp      Pointer to instance-specific data
+ *                        (for one dyndb section).
+ */
 VISIBLE isc_result_t
-dynamic_driver_init(isc_mem_t *mctx, const char *name, const char * const *argv,
-		    dns_dyndb_arguments_t *dyndb_args)
+dyndb_init(isc_mem_t *mctx, const char *name, const char *parameters,
+	   const char *file, unsigned long line, const dns_dyndbctx_t *dctx,
+	   void **instp)
 {
-	dns_dbimplementation_t *ldapdb_imp_new = NULL;
+	ldap_instance_t *inst = NULL;
 	isc_result_t result;
+	static isc_once_t library_init_once = ISC_ONCE_INIT;
 
 	REQUIRE(name != NULL);
-	REQUIRE(argv != NULL);
-	REQUIRE(dyndb_args != NULL);
+	REQUIRE(parameters != NULL);
+	REQUIRE(dctx != NULL);
+	REQUIRE(instp != NULL && *instp == NULL);
 
-	log_debug(2, "registering dynamic ldap driver for %s.", name);
+	RUNTIME_CHECK(isc_once_do(&library_init_once, library_init)
+		      == ISC_R_SUCCESS);
 
 	/*
-	 * We need to discover what rdataset methods does
-	 * dns_rdatalist_tordataset use. We then make a copy for ourselves
-	 * with the exception that we modify the disassociate method to free
-	 * the rdlist we allocate for it in clone_rdatalist_to_rdataset().
+	 * Depending on how dlopen() was called, we may not have
+	 * access to named's global namespace, in which case we need
+	 * to initialize libisc/libdns
 	 */
+	if (dctx->refvar != &isc_bind9) {
+		isc_lib_register();
+		isc_log_setcontext(dctx->lctx);
+		dns_log_setcontext(dctx->lctx);
+	}
 
-	/* Register new DNS DB implementation. */
-	result = dns_db_register(ldapdb_impname, &ldapdb_associate, NULL, mctx,
-				 &ldapdb_imp_new);
-	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
-		return result;
-	else if (result == ISC_R_SUCCESS)
-		ldapdb_imp = ldapdb_imp_new;
+	isc_hash_set_initializer(dctx->hashinit);
+
+	log_debug(2, "registering dynamic ldap driver for %s.", name);
 
 	/* Finally, create the instance. */
-	result = manager_create_db_instance(mctx, name, argv, dyndb_args);
+	CHECK(new_ldap_instance(mctx, name, parameters, file, line, dctx,
+				&inst));
+	*instp = inst;
 
+cleanup:
 	return result;
 }
 
+/*
+ * Driver destroy is called for every instance on every reload and then once
+ * during shutdown.
+ *
+ * @param[out] instp Pointer to instance-specific data (for one dyndb section).
+ */
 VISIBLE void
-dynamic_driver_destroy(void)
-{
-	/* Only unregister the implementation if it was registered by us. */
-	if (ldapdb_imp != NULL)
-		dns_db_unregister(&ldapdb_imp);
-
-	destroy_manager();
+dyndb_destroy(void **instp) {
+	destroy_ldap_instance((ldap_instance_t **)instp);
 }
diff --git a/src/ldap_driver.h b/src/ldap_driver.h
index 73c4827..62d50f6 100644
--- a/src/ldap_driver.h
+++ b/src/ldap_driver.h
@@ -19,9 +19,13 @@ typedef struct ldapdb ldapdb_t;
 
 isc_result_t
 ldapdb_create(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type,
-	      dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
-	      void *driverarg, dns_db_t **dbp) ATTR_NONNULL(1,2,6,8);
+	      dns_rdataclass_t rdclass, void *driverarg, dns_db_t **dbp)
+	      ATTR_NONNULL(1,2,5,6);
 
+isc_result_t
+ldapdb_associate(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type,
+		 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+		 void *driverarg, dns_db_t **dbp) ATTR_NONNULL(1,2,7,8);
 dns_db_t *
 ldapdb_get_rbtdb(dns_db_t *db) ATTR_NONNULLS;
 
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index ad6e417..a11751d 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4,7 +4,7 @@
 
 #include "config.h"
 
-#include <dns/dynamic_db.h>
+#include <dns/dyndb.h>
 #include <dns/diff.h>
 #include <dns/journal.h>
 #include <dns/rbt.h>
@@ -42,6 +42,7 @@
 #include <isc/string.h>
 
 #include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
 
 #include <alloca.h>
 #define LDAP_DEPRECATED 1
@@ -77,7 +78,6 @@
 #include "syncrepl.h"
 #include "util.h"
 #include "zone.h"
-#include "zone_manager.h"
 #include "zone_register.h"
 #include "rbt_helper.h"
 #include "fwd_register.h"
@@ -133,7 +133,8 @@ struct ldap_instance {
 	isc_mem_t		*mctx;
 
 	/* These are needed for zone creation. */
-	const char *		db_name;
+	char *			db_name;
+	dns_dbimplementation_t	*db_imp;
 	dns_view_t		*view;
 	dns_zonemgr_t		*zmgr;
 
@@ -184,12 +185,6 @@ struct ldap_connection {
 	unsigned int		tries;
 };
 
-/*
- * Constants.
- */
-
-extern const char *ldapdb_impname;
-
 /* Supported authentication types. */
 const ldap_auth_pair_t supported_ldap_auth[] = {
 	{ AUTH_NONE,	"none"		},
@@ -206,7 +201,6 @@ static const setting_t settings_local_default[] = {
 	{ "connections",		no_default_uint		},
 	{ "reconnect_interval",		no_default_uint		},
 	{ "timeout",			no_default_uint		},
-	{ "cache_ttl",			no_default_string	}, /* No longer supported */
 	{ "base",			no_default_string	},
 	{ "auth_method",		no_default_string	},
 	{ "auth_method_enum",		no_default_uint		},
@@ -220,12 +214,9 @@ static const setting_t settings_local_default[] = {
 	{ "sasl_password",		no_default_string	},
 	{ "krb5_keytab",		no_default_string	},
 	{ "fake_mname",			no_default_string	},
-	{ "zone_refresh",		no_default_string	}, /* No longer supported */
-	{ "psearch",			no_default_string	}, /* No longer supported */
 	{ "ldap_hostname",		no_default_string	},
 	{ "sync_ptr",			no_default_boolean	},
 	{ "dyn_update",			no_default_boolean	},
-	{ "serial_autoincrement",	no_default_string	}, /* No longer supported */
 	{ "verbose_checks",		no_default_boolean	},
 	{ "directory",			no_default_string	},
 	{ "nsec3param",			default_string("0 0 0 00")	}, /* NSEC only */
@@ -238,6 +229,50 @@ static const setting_t settings_local_default[] = {
 	end_of_settings
 };
 
+/**
+ * This is list of values configurable in dyndb section of named.conf.
+ * Names and data types must match settings_local_default.
+ * Settings which are not user-configurable must be omitted from this structure.
+ */
+static cfg_clausedef_t
+dyndb_ldap_conf_clauses[] = {
+	{ "auth_method",        &cfg_type_qstring,	0	},
+	{ "base",               &cfg_type_qstring,	0	},
+	{ "bind_dn",            &cfg_type_qstring,	0	},
+	{ "connections",        &cfg_type_uint32,	0	},
+	{ "directory",          &cfg_type_qstring,	0	},
+	{ "dyn_update",         &cfg_type_boolean,	0	},
+	{ "fake_mname",         &cfg_type_qstring,	0	},
+	{ "krb5_keytab",        &cfg_type_qstring,	0	},
+	{ "krb5_principal",     &cfg_type_qstring,	0	},
+	{ "ldap_hostname",      &cfg_type_qstring,	0	},
+	{ "password",           &cfg_type_sstring,	0	},
+	{ "reconnect_interval", &cfg_type_uint32,	0	},
+	{ "sasl_auth_name",     &cfg_type_qstring,	0	},
+	{ "sasl_mech",          &cfg_type_qstring,	0	},
+	{ "sasl_password",      &cfg_type_qstring,	0	},
+	{ "sasl_realm",         &cfg_type_qstring,	0	},
+	{ "sasl_user",          &cfg_type_qstring,	0	},
+	{ "server_id",          &cfg_type_qstring,	0	},
+	{ "sync_ptr",           &cfg_type_boolean,	0	},
+	{ "timeout",            &cfg_type_uint32,	0	},
+	{ "uri",                &cfg_type_qstring,	0	},
+	{ "verbose_checks",     &cfg_type_boolean,	0	},
+	{ NULL,			NULL,			0	}
+};
+
+static cfg_clausedef_t *
+dyndb_ldap_clausulesets[] = {
+	dyndb_ldap_conf_clauses,
+	NULL
+};
+
+/** Entry point for configuration parser used on dyndb section of named.conf. */
+static cfg_type_t cfg_type_dyndb_conf = {
+	"dyndb_ldap_conf", cfg_parse_mapbody, cfg_print_mapbody,
+	cfg_doc_mapbody, &cfg_rep_map, dyndb_ldap_clausulesets
+};
+
 /** Global settings from idnsConfig object. */
 static setting_t settings_global_default[] = {
 	{ "dyn_update",		no_default_boolean					},
@@ -351,14 +386,6 @@ validate_local_instance_settings(ldap_instance_t *inst, settings_set_t *set) {
 	const char *dir_name = NULL;
 	isc_boolean_t dir_default;
 	ld_string_t *buff = NULL;
-
-	/* handle cache_ttl, psearch, serial_autoincrement, and zone_refresh
-	 * in special way */
-	const char *obsolete_value = NULL;
-	char *obsolete_options[] = {"cache_ttl", "psearch",
-				    "serial_autoincrement", "zone_refresh",
-				    NULL};
-
 	char print_buff[PRINT_BUFF_SIZE];
 	const char *auth_method_str = NULL;
 	ldap_auth_t auth_method_enum = AUTH_INVALID;
@@ -485,12 +512,6 @@ validate_local_instance_settings(ldap_instance_t *inst, settings_set_t *set) {
 			 "are untested; expect problems");
 	}
 
-	for (char **option = obsolete_options; *option != NULL; option++) {
-		CHECK(setting_get_str(*option, set, &obsolete_value));
-		if (memcmp("", obsolete_value, 1) != 0)
-			log_error("option '%s' is not supported, ignoring", *option);
-	}
-
 	if (settings_set_isfilled(set) != ISC_TRUE)
 		result = ISC_R_FAILURE;
 
@@ -505,13 +526,12 @@ cleanup:
 
 #define PRINT_BUFF_SIZE 255
 isc_result_t
-new_ldap_instance(isc_mem_t *mctx, const char *db_name,
-		  const char * const *argv, dns_dyndb_arguments_t *dyndb_args,
-		  isc_task_t *task, ldap_instance_t **ldap_instp)
+new_ldap_instance(isc_mem_t *mctx, const char *db_name, const char *parameters,
+		  const char *file, unsigned long line,
+		  const dns_dyndbctx_t *dctx, ldap_instance_t **ldap_instp)
 {
 	isc_result_t result;
 	ldap_instance_t *ldap_inst;
-	dns_view_t *view = NULL;
 	dns_forwarders_t *named_conf_forwarders = NULL;
 	isc_buffer_t *forwarders_list = NULL;
 	const char *forward_policy = NULL;
@@ -526,30 +546,31 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 	ZERO_PTR(ldap_inst);
 	CHECK(isc_refcount_init(&ldap_inst->errors, 0));
 	isc_mem_attach(mctx, &ldap_inst->mctx);
+	CHECKED_MEM_STRDUP(mctx, db_name, ldap_inst->db_name);
+	dns_view_attach(dctx->view, &ldap_inst->view);
+	dns_zonemgr_attach(dctx->zmgr, &ldap_inst->zmgr);
+	isc_task_attach(dctx->task, &ldap_inst->task);
 
-	ldap_inst->db_name = db_name;
-	view = dns_dyndb_get_view(dyndb_args);
-	dns_view_attach(view, &ldap_inst->view);
-	ldap_inst->zmgr = dns_dyndb_get_zonemgr(dyndb_args);
-	ldap_inst->task = task;
 	ldap_inst->watcher = 0;
 	CHECK(sync_ctx_init(ldap_inst->mctx, ldap_inst, &ldap_inst->sctx));
 
 	isc_string_printf_truncate(settings_name, PRINT_BUFF_SIZE,
 				   SETTING_SET_NAME_LOCAL " for database %s",
-				   db_name);
+				   ldap_inst->db_name);
 	CHECK(settings_set_create(mctx, settings_local_default,
 	      sizeof(settings_local_default), settings_name,
 	      &settings_default_set, &ldap_inst->local_settings));
 
 	isc_string_printf_truncate(settings_name, PRINT_BUFF_SIZE,
 				   SETTING_SET_NAME_GLOBAL " for database %s",
-				   db_name);
+				   ldap_inst->db_name);
 	CHECK(settings_set_create(mctx, settings_global_default,
 	      sizeof(settings_global_default), settings_name,
 	      ldap_inst->local_settings, &ldap_inst->global_settings));
 
-	CHECK(settings_set_fill(ldap_inst->local_settings, argv));
+	CHECK(setting_set_parse_conf(mctx, ldap_inst->db_name,
+				     &cfg_type_dyndb_conf, parameters, file,
+				     line, ldap_inst->local_settings));
 
 	/* copy global forwarders setting for configuration roll back in
 	 * configure_zone_forwarders() */
@@ -573,7 +594,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 		 *
 		 * Warn-only semantics is implemented in BIND RT#41441,
 		 * this code can be removed when we rebase to BIND 9.11. */
-		CHECK(sync_task_add(ldap_inst->sctx, task));
+		CHECK(sync_task_add(ldap_inst->sctx, ldap_inst->task));
 		gfwdevent = (ldap_globalfwd_handleez_t *)isc_event_allocate(
 					ldap_inst->mctx, ldap_inst,
 					LDAPDB_EVENT_GLOBALFWD_HANDLEEZ,
@@ -586,7 +607,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 		gfwdevent->warn_only = (named_conf_forwarders->fwdpolicy
 					== dns_fwdpolicy_first);
 
-		isc_task_send(task, (isc_event_t **)&gfwdevent);
+		isc_task_send(ldap_inst->task, (isc_event_t **)&gfwdevent);
 
 	} else if (result == ISC_R_NOTFOUND) {
 		/* global forwarders are not configured */
@@ -639,6 +660,10 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 	CHECK(ldap_pool_create(mctx, connections, &ldap_inst->pool));
 	CHECK(ldap_pool_connect(ldap_inst->pool, ldap_inst));
 
+	/* Register new DNS DB implementation. */
+	CHECK(dns_db_register(ldap_inst->db_name, &ldapdb_associate, ldap_inst,
+			      mctx, &ldap_inst->db_imp));
+
 	/* Start the watcher thread */
 	result = isc_thread_create(ldap_syncrepl_watcher, ldap_inst,
 				   &ldap_inst->watcher);
@@ -663,7 +688,6 @@ void
 destroy_ldap_instance(ldap_instance_t **ldap_instp)
 {
 	ldap_instance_t *ldap_inst;
-	const char *db_name;
 
 	REQUIRE(ldap_instp != NULL);
 
@@ -671,8 +695,6 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp)
 	if (ldap_inst == NULL)
 		return;
 
-	db_name = ldap_inst->db_name; /* points to DB instance: outside ldap_inst */
-
 	if (ldap_inst->watcher != 0) {
 		ldap_inst->exiting = ISC_TRUE;
 		/*
@@ -695,7 +717,14 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp)
 	mldap_destroy(&ldap_inst->mldapdb);
 
 	ldap_pool_destroy(&ldap_inst->pool);
-	dns_view_detach(&ldap_inst->view);
+	if (ldap_inst->db_imp != NULL)
+		dns_db_unregister(&ldap_inst->db_imp);
+	if (ldap_inst->view != NULL)
+		dns_view_detach(&ldap_inst->view);
+	if (ldap_inst->zmgr != NULL)
+		dns_zonemgr_detach(&ldap_inst->zmgr);
+	if (ldap_inst->task != NULL)
+		isc_task_detach(&ldap_inst->task);
 
 	DESTROYLOCK(&ldap_inst->kinit_lock);
 
@@ -709,10 +738,13 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp)
 				     ldap_instance_untaint_start(ldap_inst));
 	isc_refcount_destroy(&ldap_inst->errors);
 
+	if (ldap_inst->db_name != NULL) {
+		log_debug(1, "LDAP instance '%s' destroyed", ldap_inst->db_name);
+		isc_mem_free(ldap_inst->mctx, ldap_inst->db_name);
+	}
 	MEM_PUT_AND_DETACH(ldap_inst);
 
 	*ldap_instp = NULL;
-	log_debug(1, "LDAP instance '%s' destroyed", db_name);
 }
 
 static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
@@ -916,7 +948,7 @@ create_zone(ldap_instance_t * const inst, const char * const dn,
 	isc_result_t result;
 	dns_zone_t *raw = NULL;
 	dns_zone_t *secure = NULL;
-	const char *ldap_argv[2];
+	const char *ldap_argv[1] = { inst->db_name };
 	const char *rbt_argv[1] = { "rbt" };
 	sync_state_t sync_state;
 	isc_task_t *task = NULL;
@@ -926,9 +958,6 @@ create_zone(ldap_instance_t * const inst, const char * const dn,
 	REQUIRE(name != NULL);
 	REQUIRE(rawp != NULL && *rawp == NULL);
 
-	ldap_argv[0] = ldapdb_impname;
-	ldap_argv[1] = inst->db_name;
-
 	result = zone_unload_ifempty(inst->view, name);
 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
 		goto cleanup;
@@ -938,7 +967,8 @@ create_zone(ldap_instance_t * const inst, const char * const dn,
 	dns_zone_setclass(raw, dns_rdataclass_in);
 	dns_zone_settype(raw, dns_zone_master);
 	/* dns_zone_setview(raw, view); */
-	CHECK(dns_zone_setdbtype(raw, 2, ldap_argv));
+	CHECK(dns_zone_setdbtype(raw, sizeof(ldap_argv)/sizeof(ldap_argv[0]),
+				 ldap_argv));
 	CHECK(configure_paths(inst->mctx, inst, raw, ISC_FALSE));
 
 	if (want_secure == ISC_FALSE) {
@@ -3654,7 +3684,7 @@ update_zone(isc_task_t *task, isc_event_t *event)
 {
 	ldap_syncreplevent_t *pevent = (ldap_syncreplevent_t *)event;
 	isc_result_t result ;
-	ldap_instance_t *inst = NULL;
+	ldap_instance_t *inst = pevent->inst;
 	isc_mem_t *mctx;
 	dns_name_t prevname;
 	ldap_entry_t *entry = pevent->entry;
@@ -3662,7 +3692,6 @@ update_zone(isc_task_t *task, isc_event_t *event)
 	mctx = pevent->mctx;
 	dns_name_init(&prevname, NULL);
 
-	CHECK(manager_get_ldap_instance(pevent->dbname, &inst));
 	INSIST(task == inst->task); /* For task-exclusive mode */
 
 	if (SYNCREPL_DEL(pevent->chgtype)) {
@@ -3673,6 +3702,9 @@ update_zone(isc_task_t *task, isc_event_t *event)
 							  task));
 		else if (entry->class & LDAP_ENTRYCLASS_FORWARD)
 			CHECK(ldap_parse_fwd_zoneentry(entry, inst));
+		else
+			FATAL_ERROR(__FILE__, __LINE__,
+				    "update_zone: unexpected entry class");
 	}
 
 cleanup:
@@ -3687,7 +3719,6 @@ cleanup:
 			    "Zones can be outdated, run `rndc reload`",
 			    ldap_entry_logname(entry));
 
-	isc_mem_free(mctx, pevent->dbname);
 	if (pevent->prevdn != NULL)
 		isc_mem_free(mctx, pevent->prevdn);
 	ldap_entry_destroy(&entry);
@@ -3701,13 +3732,12 @@ update_config(isc_task_t * task, isc_event_t *event)
 {
 	ldap_syncreplevent_t *pevent = (ldap_syncreplevent_t *)event;
 	isc_result_t result;
-	ldap_instance_t *inst = NULL;
+	ldap_instance_t *inst = pevent->inst;
 	ldap_entry_t *entry = pevent->entry;
 	isc_mem_t *mctx;
 
 	mctx = pevent->mctx;
 
-	CHECK(manager_get_ldap_instance(pevent->dbname, &inst));
 	INSIST(task == inst->task); /* For task-exclusive mode */
 	CHECK(ldap_parse_configentry(entry, inst));
 
@@ -3722,7 +3752,6 @@ cleanup:
 			    ldap_entry_logname(entry));
 
 	ldap_entry_destroy(&entry);
-	isc_mem_free(mctx, pevent->dbname);
 	isc_mem_detach(&mctx);
 	isc_event_free(&event);
 	isc_task_detach(&task);
@@ -3733,13 +3762,12 @@ update_serverconfig(isc_task_t * task, isc_event_t *event)
 {
 	ldap_syncreplevent_t *pevent = (ldap_syncreplevent_t *)event;
 	isc_result_t result;
-	ldap_instance_t *inst = NULL;
+	ldap_instance_t *inst = pevent->inst;
 	ldap_entry_t *entry = pevent->entry;
 	isc_mem_t *mctx;
 
 	mctx = pevent->mctx;
 
-	CHECK(manager_get_ldap_instance(pevent->dbname, &inst));
 	INSIST(task == inst->task); /* For task-exclusive mode */
 	CHECK(ldap_parse_serverconfigentry(entry, inst));
 
@@ -3754,7 +3782,6 @@ cleanup:
 			    ldap_entry_logname(entry));
 
 	ldap_entry_destroy(&entry);
-	isc_mem_free(mctx, pevent->dbname);
 	isc_mem_detach(&mctx);
 	isc_event_free(&event);
 	isc_task_detach(&task);
@@ -3774,7 +3801,7 @@ update_record(isc_task_t *task, isc_event_t *event)
 	/* syncrepl event */
 	ldap_syncreplevent_t *pevent = (ldap_syncreplevent_t *)event;
 	isc_result_t result;
-	ldap_instance_t *inst = NULL;
+	ldap_instance_t *inst = pevent->inst;
 	isc_mem_t *mctx;
 	settings_set_t *zone_settings = NULL;
 	dns_zone_t *raw = NULL;
@@ -3811,7 +3838,6 @@ update_record(isc_task_t *task, isc_event_t *event)
 	dns_name_init(&prevname, NULL);
 	dns_name_init(&prevorigin, NULL);
 
-	CHECK(manager_get_ldap_instance(pevent->dbname, &inst));
 	CHECK(zr_get_zone_ptr(inst->zone_register, &entry->zone_name, &raw, &secure));
 	zone_found = ISC_TRUE;
 
@@ -3984,7 +4010,6 @@ cleanup:
 	if (secure != NULL)
 		dns_zone_detach(&secure);
 	ldapdb_rdatalist_destroy(mctx, &rdatalist);
-	isc_mem_free(mctx, pevent->dbname);
 	if (pevent->prevdn != NULL)
 		isc_mem_free(mctx, pevent->prevdn);
 	ldap_entry_destroy(&entry);
@@ -4055,8 +4080,6 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t **entryp, int chgtype)
 	dns_name_t *zone_name = NULL;
 	dns_zone_t *zone_ptr = NULL;
 	char *dn = NULL;
-	char *dbname = NULL;
-	isc_mem_t *mctx = NULL;
 	isc_taskaction_t action = NULL;
 	isc_task_t *task = NULL;
 	isc_boolean_t synchronous;
@@ -4069,10 +4092,6 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t **entryp, int chgtype)
 		  SYNCREPL_ADD(chgtype), SYNCREPL_DEL(chgtype),
 		  SYNCREPL_MOD(chgtype));
 
-	isc_mem_attach(inst->mctx, &mctx);
-
-	CHECKED_MEM_STRDUP(mctx, inst->db_name, dbname);
-
 	if (entry->class & LDAP_ENTRYCLASS_MASTER)
 		zone_name = &entry->fqdn;
 	else
@@ -4128,8 +4147,9 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t **entryp, int chgtype)
 		goto cleanup;
 	}
 
-	pevent->mctx = mctx;
-	pevent->dbname = dbname;
+	pevent->mctx = NULL;
+	isc_mem_attach(inst->mctx, &pevent->mctx);
+	pevent->inst = inst;
 	pevent->prevdn = NULL;
 	pevent->chgtype = chgtype;
 	pevent->entry = entry;
@@ -4148,11 +4168,8 @@ cleanup:
 	if (pevent != NULL) {
 		/* Event was not sent */
 		sync_concurr_limit_signal(inst->sctx);
-
-		if (dbname != NULL)
-			isc_mem_free(mctx, dbname);
-		if (mctx != NULL)
-			isc_mem_detach(&mctx);
+		if (pevent->mctx != NULL)
+			isc_mem_detach(&pevent->mctx);
 		ldap_entry_destroy(entryp);
 		if (task != NULL)
 			isc_task_detach(&task);
@@ -4394,7 +4411,7 @@ int ldap_sync_intermediate (
 
 	sync_state_get(inst->sctx, &state);
 	if (state == sync_datainit) {
-		result = sync_barrier_wait(inst->sctx, inst->db_name);
+		result = sync_barrier_wait(inst->sctx, inst);
 		if (result != ISC_R_SUCCESS) {
 			log_error_r("%s: sync_barrier_wait() failed for "
 				    "instance '%s'", __func__, inst->db_name);
@@ -4447,7 +4464,7 @@ int ATTR_NONNULLS ATTR_CHECKRESULT ldap_sync_search_result (
 	INSIST(state == sync_configinit || state == sync_finished);
 
 	if (state == sync_configinit) {
-		result = sync_barrier_wait(inst->sctx, inst->db_name);
+		result = sync_barrier_wait(inst->sctx, inst);
 		if (result != ISC_R_SUCCESS) {
 			log_error_r("%s: sync_barrier_wait() failed for "
 				    "instance '%s'", __func__, inst->db_name);
diff --git a/src/ldap_helper.h b/src/ldap_helper.h
index a491bae..6cfece5 100644
--- a/src/ldap_helper.h
+++ b/src/ldap_helper.h
@@ -9,6 +9,7 @@
 
 #include <isc/eventclass.h>
 #include <isc/util.h>
+#include <isccfg/cfg.h>
 
 #include <ldap.h>
 
@@ -40,9 +41,9 @@ void free_rdatalist(isc_mem_t *mctx, dns_rdatalist_t *rdlist) ATTR_NONNULLS;
  */
 
 isc_result_t
-new_ldap_instance(isc_mem_t *mctx, const char *db_name,
-		  const char * const *argv, dns_dyndb_arguments_t *dyndb_args,
-		  isc_task_t *task, ldap_instance_t **ldap_instp) ATTR_NONNULLS;
+new_ldap_instance(isc_mem_t *mctx, const char *db_name, const char *parameters,
+		  const char *file, unsigned long line,
+		  const dns_dyndbctx_t *dctx, ldap_instance_t **ldap_instp) ATTR_NONNULLS;
 void destroy_ldap_instance(ldap_instance_t **ldap_inst) ATTR_NONNULLS;
 
 isc_result_t
diff --git a/src/settings.c b/src/settings.c
index 3692dae..37e6e5c 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -9,6 +9,7 @@
 #include <isc/string.h>
 #include <isc/int.h>
 #include <isc/parseint.h>
+
 #include <dns/name.h>
 
 #include <ctype.h>
@@ -553,66 +554,72 @@ settings_set_free(settings_set_t **set) {
 }
 
 /**
- * Set all values specified by vector of strings to setting set. Setting name
- * is separated from it's argument with one or more characters defined by
- * @link SETTING_NAME_SEPARATORS@endlink.
- *
- * @retval ISC_R_SUCCESS All strings in argument vector were processed and set.
- * @retval Others        Memory or parsing errors.
- *
- * @warning One string in argument vector is limited to
- * @link SETTING_LINE_MAXLENGTH@endlink.
- *
- * @note
- * @code{.txt}
- * Calling settings_set_fill() with argument array
+ * Append textlen bytes from text to isc_buffer pointed to by closure.
  *
- * {"setting1	value 1 ",
- *  "bind_dn cn=Directory manager" }
- *
- * will result in setting values to two separate settings:
+ * @pre closure is an initialized isc_buffer with autoreallocation enabled.
+ */
+static void
+cfg_printer(void *closure, const char *text, int textlen) {
+	isc_buffer_t *logbuffer = closure;
+
+	REQUIRE(logbuffer != NULL);
+	REQUIRE(logbuffer->autore == ISC_TRUE);
+
+	isc_buffer_putmem(logbuffer, (const unsigned char *)text, textlen);
+}
+
+/**
+ * Copy values from cfg map to set of settings.
+ * Only setting names specified in set of settings are copied.
  *
- * "setting1" = "value 1 "
- * "bind_dn"  = "cn=Directory manager"
+ * @param[in]  config
+ * @param[out] set
  *
- * Please note the positions of white spaces.
- * @endcode
+ * @retval ISC_R_SUCCESS Items listed in set of settings were copied from cfg map.
+ * @retval Others        Memory or parsing errors.
  */
-isc_result_t
-settings_set_fill(settings_set_t *set, const char *const *argv)
+static isc_result_t
+settings_set_fill(const cfg_obj_t *config, settings_set_t *set)
 {
 	isc_result_t result;
-	int i;
-	const char *name;
-	char *value;
-
-	for (i = 0; argv[i] != NULL; i++) {
-		char buff[SETTING_LINE_MAXLENGTH] = "";
-		CHECK(isc_string_copy(buff, SETTING_LINE_MAXLENGTH, argv[i]));
-		value = buff;
-		name = isc_string_separate(&value, SETTING_NAME_SEPARATORS);
-		if (name == NULL || value == NULL)
-			CLEANUP_WITH(ISC_R_UNEXPECTEDEND);
-		value += strspn(value, SETTING_NAME_SEPARATORS);
-		if (setting_find(name, set, ISC_FALSE, ISC_TRUE, NULL)
-		    != ISC_R_NOTFOUND) {
-			log_error("multiple definitions of setting '%s' in "
-				  "set of settings '%s'", name, set->name);
-			CLEANUP_WITH(ISC_R_EXISTS);
+	setting_t *setting;
+	isc_buffer_t *buf_value = NULL;
+	const cfg_obj_t *cfg_value;
+	const char *str_value;
+
+	REQUIRE(cfg_obj_ismap(config) == ISC_TRUE);
+
+	CHECK(isc_buffer_allocate(set->mctx, &buf_value, ISC_BUFFER_INCR));
+	isc_buffer_setautorealloc(buf_value, ISC_TRUE);
+
+	for (setting = set->first_setting;
+	     setting->name != NULL;
+	     setting++) {
+		cfg_value = NULL;
+		result = cfg_map_get(config, setting->name, &cfg_value);
+		if (result == ISC_R_NOTFOUND)
+			continue; /* setting not configured in map */
+		else if (result != ISC_R_SUCCESS)
+			goto cleanup;
+		if (cfg_obj_isstring(cfg_value)) {
+			/* this avoids additional quotes around the string */
+			str_value = cfg_obj_asstring(cfg_value);
+		} else {
+			cfg_printx(cfg_value, 0, cfg_printer, buf_value);
+			isc_buffer_putmem(buf_value, (unsigned char *)"\0", 1);
+			str_value = isc_buffer_base(buf_value);
 		}
-		result = setting_set(name, set, value);
+		result = set_value(set->mctx, set, setting, str_value);
 		if (result != ISC_R_SUCCESS && result != ISC_R_IGNORE)
 			goto cleanup;
+		isc_buffer_clear(buf_value);
 	}
 
-	return ISC_R_SUCCESS;
-
 cleanup:
-	log_error_r("cannot parse settings from '%s': "
-		    "problematic configuration line:"
-		    "\n%s\n"
-		    "error code", set->name, argv[i]);
-	/* TODO: Free memory in case of error. */
+	if (result != ISC_R_SUCCESS)
+		log_error_r("cannot parse settings for '%s'", set->name);
+	if (buf_value != NULL)
+		isc_buffer_free(&buf_value);
 	return result;
 }
 
@@ -644,6 +651,75 @@ settings_set_isfilled(settings_set_t *set) {
 	return isfiled;
 }
 
+/**
+ * Parse string with dyndb configuration and fill in settings_set_t structure.
+ *
+ * @param[in]  name		name of dyndb instance
+ * @param[in]  cfg_type_conf	configuration grammar for ISC parser
+ * @param[in]  parameters	string with complete dyndb configuration
+ * @param[in]  file		name of configuration file
+ * @param[in]  line		line on which config starts
+ * @param[out] settings		set of settings filled with values from config
+ *
+ * @pre Names and data types of respective paremeters
+ * 	in cfg_type_conf and set of settings must match.
+ */
+isc_result_t
+setting_set_parse_conf(isc_mem_t *mctx, const char *name,
+		       cfg_type_t *cfg_type_conf, const char *parameters,
+		       const char *file, unsigned long line,
+		       settings_set_t *settings)
+{
+	isc_result_t result;
+	cfg_obj_t *config = NULL;
+	isc_buffer_t in_buf;
+	isc_buffer_t *log_buf = NULL;
+	cfg_parser_t *parser = NULL;
+	unsigned int len;
+
+	REQUIRE(parameters != NULL);
+
+	CHECK(isc_buffer_allocate(mctx, &log_buf, ISC_BUFFER_INCR));
+	isc_buffer_setautorealloc(log_buf, ISC_TRUE);
+
+	len = strlen(parameters);
+	isc_buffer_constinit(&in_buf, parameters, len);
+	isc_buffer_add(&in_buf, len);
+
+	CHECK(cfg_parser_create(mctx, dns_lctx, &parser));
+	result = cfg_parse_buffer2(parser, &in_buf, name, cfg_type_conf,
+				   &config);
+	if (result == ISC_R_SUCCESS) {
+		cfg_printx(config, CFG_PRINTER_XKEY, cfg_printer, log_buf);
+		cfg_obj_log(config, dns_lctx, ISC_LOG_DEBUG(10),
+			    "configuration for dyndb instance '%s' "
+			    "(starting in file %s on line %lu):\n"
+			    "%.*s",
+			    name, file, line, isc_buffer_usedlength(log_buf),
+			    (char *)isc_buffer_base(log_buf));
+	} else {
+		log_error("configuration for dyndb instance '%s' "
+			  "(starting in file %s on line %lu) is invalid",
+			  name, file, line);
+		cfg_print_grammar(cfg_type_conf, cfg_printer, log_buf);
+		log_info("expected grammar:\n"
+			 "%.*s", isc_buffer_usedlength(log_buf),
+			 (char *)isc_buffer_base(log_buf));
+		goto cleanup;
+	}
+
+	CHECK(settings_set_fill(config, settings));
+
+cleanup:
+	if (log_buf != NULL)
+		isc_buffer_free(&log_buf);
+	if (config != NULL)
+		cfg_obj_destroy(parser, &config);
+	if (parser != NULL)
+		cfg_parser_destroy(&parser);
+	return result;
+}
+
 isc_result_t
 get_enum_description(const enum_txt_assoc_t *map, int value, const char **desc) {
 	const enum_txt_assoc_t *record;
diff --git a/src/settings.h b/src/settings.h
index 9bc4176..16a1e63 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -6,12 +6,13 @@
 #define _LD_SETTINGS_H_
 
 #include <isc/types.h>
+
+#include <isccfg/grammar.h>
+
 #include "types.h"
 #include "str.h"
 #include "ldap_entry.h"
 
-#define SETTING_LINE_MAXLENGTH 255
-#define SETTING_NAME_SEPARATORS " \t"
 #define SETTING_SET_NAME_LOCAL  "named.conf"
 #define SETTING_SET_NAME_SERVER "LDAP idnsServerConfig object"
 #define SETTING_SET_NAME_GLOBAL "LDAP idnsConfig object"
@@ -82,8 +83,10 @@ void
 settings_set_free(settings_set_t **set) ATTR_NONNULLS;
 
 isc_result_t
-settings_set_fill(settings_set_t *set, const char *const *argv)
-		  ATTR_NONNULLS ATTR_CHECKRESULT;
+setting_set_parse_conf(isc_mem_t *mctx, const char *name,
+		       cfg_type_t *cfg_type_conf, const char *parameters,
+		       const char *file, unsigned long line,
+		       settings_set_t *settings) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 isc_boolean_t
 settings_set_isfilled(settings_set_t *set) ATTR_NONNULLS ATTR_CHECKRESULT;
diff --git a/src/syncrepl.c b/src/syncrepl.c
index 0079644..6ed8051 100644
--- a/src/syncrepl.c
+++ b/src/syncrepl.c
@@ -15,7 +15,6 @@
 #include "util.h"
 #include "semaphore.h"
 #include "syncrepl.h"
-#include "zone_manager.h"
 
 #define LDAPDB_EVENT_SYNCREPL_BARRIER	(LDAPDB_EVENTCLASS + 2)
 #define LDAPDB_EVENT_SYNCREPL_FINISH	(LDAPDB_EVENTCLASS + 3)
@@ -109,7 +108,7 @@ struct sync_ctx {
  */
 struct sync_barrierev {
 	ISC_EVENT_COMMON(sync_barrierev_t);
-	const char	*dbname;
+	ldap_instance_t	*inst;
 	sync_ctx_t	*sctx;
 };
 
@@ -122,7 +121,6 @@ struct sync_barrierev {
 void
 finish(isc_task_t *task, isc_event_t *event) {
 	isc_result_t result = ISC_R_SUCCESS;
-	ldap_instance_t *inst = NULL;
 	sync_barrierev_t *bev = NULL;
 	sync_state_t new_state;
 
@@ -130,7 +128,6 @@ finish(isc_task_t *task, isc_event_t *event) {
 	REQUIRE(event != NULL);
 
 	bev = (sync_barrierev_t *)event;
-	CHECK(manager_get_ldap_instance(bev->dbname, &inst));
 	log_debug(1, "sync_barrier_wait(): finish reached");
 	LOCK(&bev->sctx->mutex);
 	switch (bev->sctx->state) {
@@ -152,9 +149,8 @@ finish(isc_task_t *task, isc_event_t *event) {
 	BROADCAST(&bev->sctx->cond);
 	UNLOCK(&bev->sctx->mutex);
 	if (new_state == sync_finished)
-		activate_zones(task, inst);
+		activate_zones(task, bev->inst);
 
-cleanup:
 	if (result != ISC_R_SUCCESS)
 		log_error_r("syncrepl finish() failed");
 	isc_event_free(&event);
@@ -162,12 +158,12 @@ cleanup:
 }
 
 static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
-sync_finishev_create(sync_ctx_t *sctx, const char *inst_name,
+sync_finishev_create(sync_ctx_t *sctx, ldap_instance_t *inst,
 		      sync_barrierev_t **evp) {
 	sync_barrierev_t *ev = NULL;
 
 	REQUIRE(sctx != NULL);
-	REQUIRE(inst_name != NULL);
+	REQUIRE(inst != NULL);
 	REQUIRE(evp != NULL && *evp == NULL);
 
 	ev = (sync_barrierev_t *)isc_event_allocate(sctx->mctx,
@@ -177,7 +173,7 @@ sync_finishev_create(sync_ctx_t *sctx, const char *inst_name,
 	if (ev == NULL)
 		return ISC_R_NOMEMORY;
 
-	ev->dbname = inst_name;
+	ev->inst = inst;
 	ev->sctx = sctx;
 	*evp = ev;
 
@@ -203,7 +199,6 @@ sync_finishev_create(sync_ctx_t *sctx, const char *inst_name,
 void
 barrier_decrement(isc_task_t *task, isc_event_t *event) {
 	isc_result_t result = ISC_R_SUCCESS;
-	ldap_instance_t *inst = NULL;
 	sync_barrierev_t *bev = NULL;
 	sync_barrierev_t *fev = NULL;
 	isc_event_t *ev = NULL;
@@ -214,13 +209,12 @@ barrier_decrement(isc_task_t *task, isc_event_t *event) {
 	REQUIRE(event != NULL);
 
 	bev = (sync_barrierev_t *)event;
-	CHECK(manager_get_ldap_instance(bev->dbname, &inst));
 	isc_refcount_decrement(&bev->sctx->task_cnt, &cnt);
 	if (cnt == 0) {
 		log_debug(1, "sync_barrier_wait(): barrier reached");
 		LOCK(&bev->sctx->mutex);
 		locked = ISC_TRUE;
-		CHECK(sync_finishev_create(bev->sctx, bev->dbname, &fev));
+		CHECK(sync_finishev_create(bev->sctx, bev->inst, &fev));
 		ev = (isc_event_t *)fev;
 		isc_task_send(ldap_instance_gettask(bev->sctx->inst), &ev);
 	}
@@ -235,12 +229,12 @@ cleanup:
 }
 
 static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
-sync_barrierev_create(sync_ctx_t *sctx, const char *inst_name,
+sync_barrierev_create(sync_ctx_t *sctx, ldap_instance_t *inst,
 		      sync_barrierev_t **evp) {
 	sync_barrierev_t *ev = NULL;
 
 	REQUIRE(sctx != NULL);
-	REQUIRE(inst_name != NULL);
+	REQUIRE(inst != NULL);
 	REQUIRE(evp != NULL && *evp == NULL);
 
 	ev = (sync_barrierev_t *)isc_event_allocate(sctx->mctx,
@@ -250,7 +244,7 @@ sync_barrierev_create(sync_ctx_t *sctx, const char *inst_name,
 	if (ev == NULL)
 		return ISC_R_NOMEMORY;
 
-	ev->dbname = inst_name;
+	ev->inst = inst;
 	ev->sctx = sctx;
 	*evp = ev;
 
@@ -488,7 +482,7 @@ cleanup:
  *       enqueued before sync_barrier_wait() call.
  */
 isc_result_t
-sync_barrier_wait(sync_ctx_t *sctx, const char *inst_name) {
+sync_barrier_wait(sync_ctx_t *sctx, ldap_instance_t *inst) {
 	isc_result_t result;
 	isc_event_t *ev = NULL;
 	sync_barrierev_t *bev = NULL;
@@ -524,7 +518,7 @@ sync_barrier_wait(sync_ctx_t *sctx, const char *inst_name) {
 	     taskel != NULL;
 	     taskel = next_taskel) {
 		bev = NULL;
-		CHECK(sync_barrierev_create(sctx, inst_name, &bev));
+		CHECK(sync_barrierev_create(sctx, inst, &bev));
 		next_taskel = NEXT(taskel, link);
 		UNLINK(sctx->tasks, taskel, link);
 		ev = (isc_event_t *)bev;
diff --git a/src/syncrepl.h b/src/syncrepl.h
index ba3070a..14684ea 100644
--- a/src/syncrepl.h
+++ b/src/syncrepl.h
@@ -49,7 +49,7 @@ isc_result_t
 sync_task_add(sync_ctx_t *sctx, isc_task_t *task) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 isc_result_t
-sync_barrier_wait(sync_ctx_t *sctx, const char *inst_name) ATTR_NONNULLS ATTR_CHECKRESULT;
+sync_barrier_wait(sync_ctx_t *sctx, ldap_instance_t *inst) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 isc_result_t
 sync_concurr_limit_wait(sync_ctx_t *sctx) ATTR_NONNULLS ATTR_CHECKRESULT;
diff --git a/src/types.h b/src/types.h
index 57d5579..25ef3b9 100644
--- a/src/types.h
+++ b/src/types.h
@@ -43,7 +43,7 @@ typedef struct ldap_syncreplevent ldap_syncreplevent_t;
 struct ldap_syncreplevent {
 	ISC_EVENT_COMMON(ldap_syncreplevent_t);
 	isc_mem_t *mctx;
-	char *dbname;
+	ldap_instance_t	*inst;
 	char *prevdn;
 	int chgtype;
 	ldap_entry_t *entry;
diff --git a/src/zone_manager.c b/src/zone_manager.c
deleted file mode 100644
index 85e19fb..0000000
--- a/src/zone_manager.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2009-2014  bind-dyndb-ldap authors; see COPYING for license
- */
-
-#include <isc/mem.h>
-#include <isc/once.h>
-#include <isc/result.h>
-#include <isc/task.h>
-#include <isc/timer.h>
-#include <isc/boolean.h>
-#include <isc/util.h>
-
-#include <dns/dynamic_db.h>
-#include <dns/view.h>
-#include <dns/zone.h>
-
-#include <string.h>
-#include <unistd.h>
-
-#include "config.h"
-
-#include "bindcfg.h"
-#include "ldap_convert.h"
-#include "ldap_helper.h"
-#include "log.h"
-#include "settings.h"
-#include "util.h"
-#include "zone_manager.h"
-
-struct db_instance {
-	isc_mem_t		*mctx;
-	char			*name;
-	ldap_instance_t		*ldap_inst;
-	isc_timer_t		*timer;
-	LINK(db_instance_t)	link;
-};
-
-static isc_once_t initialize_once = ISC_ONCE_INIT;
-static isc_mutex_t instance_list_lock;
-static LIST(db_instance_t) instance_list;
-
-static void initialize_manager(void);
-static void destroy_db_instance(db_instance_t **db_instp) ATTR_NONNULLS;
-static isc_result_t find_db_instance(const char *name, db_instance_t **instance) ATTR_NONNULLS ATTR_CHECKRESULT;
-
-
-static void
-initialize_manager(void)
-{
-	INIT_LIST(instance_list);
-	isc_mutex_init(&instance_list_lock);
-	log_info("bind-dyndb-ldap version " VERSION
-		 " compiled at " __TIME__ " " __DATE__
-		 ", compiler " __VERSION__);
-	cfg_init_types();
-}
-
-void
-destroy_manager(void)
-{
-	db_instance_t *db_inst;
-	db_instance_t *next;
-
-	RUNTIME_CHECK(isc_once_do(&initialize_once, initialize_manager)
-		      == ISC_R_SUCCESS);
-
-	LOCK(&instance_list_lock);
-	db_inst = HEAD(instance_list);
-	while (db_inst != NULL) {
-		next = NEXT(db_inst, link);
-		UNLINK(instance_list, db_inst, link);
-		destroy_db_instance(&db_inst);
-		db_inst = next;
-	}
-	UNLOCK(&instance_list_lock);
-}
-
-static void ATTR_NONNULLS
-destroy_db_instance(db_instance_t **db_instp)
-{
-	db_instance_t *db_inst;
-
-	REQUIRE(db_instp != NULL && *db_instp != NULL);
-
-	db_inst = *db_instp;
-
-	if (db_inst->timer != NULL)
-		isc_timer_detach(&db_inst->timer);
-	if (db_inst->ldap_inst != NULL)
-		destroy_ldap_instance(&db_inst->ldap_inst);
-	if (db_inst->name != NULL)
-		isc_mem_free(db_inst->mctx, db_inst->name);
-
-	MEM_PUT_AND_DETACH(db_inst);
-
-	*db_instp = NULL;
-}
-
-isc_result_t
-manager_create_db_instance(isc_mem_t *mctx, const char *name,
-			   const char * const *argv,
-			   dns_dyndb_arguments_t *dyndb_args)
-{
-	isc_result_t result;
-	db_instance_t *db_inst = NULL;
-	isc_task_t *task;
-	settings_set_t *local_settings = NULL;
-
-	REQUIRE(name != NULL);
-	REQUIRE(dyndb_args != NULL);
-
-	RUNTIME_CHECK(isc_once_do(&initialize_once, initialize_manager)
-		      == ISC_R_SUCCESS);
-
-	result = find_db_instance(name, &db_inst);
-	if (result == ISC_R_SUCCESS) {
-		db_inst = NULL;
-		log_error("LDAP instance '%s' already exists", name);
-		CLEANUP_WITH(ISC_R_EXISTS);
-	}
-
-	CHECKED_MEM_GET_PTR(mctx, db_inst);
-	ZERO_PTR(db_inst);
-
-	isc_mem_attach(mctx, &db_inst->mctx);
-	CHECKED_MEM_STRDUP(mctx, name, db_inst->name);
-	task = dns_dyndb_get_task(dyndb_args);
-	CHECK(new_ldap_instance(mctx, db_inst->name, argv, dyndb_args, task,
-				&db_inst->ldap_inst));
-
-	local_settings = ldap_instance_getsettings_local(db_inst->ldap_inst);
-	CHECK(setting_get_bool("verbose_checks", local_settings, &verbose_checks));
-
-	/* instance must be in list while calling refresh_zones_from_ldap() */
-	LOCK(&instance_list_lock);
-	APPEND(instance_list, db_inst, link);
-	UNLOCK(&instance_list_lock);
-
-	return ISC_R_SUCCESS;
-
-cleanup:
-	if (db_inst != NULL)
-		destroy_db_instance(&db_inst);
-
-	return result;
-}
-
-isc_result_t
-manager_get_ldap_instance(const char *name, ldap_instance_t **ldap_inst)
-{
-	isc_result_t result;
-	db_instance_t *db_inst;
-
-	REQUIRE(name != NULL);
-	REQUIRE(ldap_inst != NULL);
-
-	RUNTIME_CHECK(isc_once_do(&initialize_once, initialize_manager)
-		      == ISC_R_SUCCESS);
-	db_inst = NULL;
-	CHECK(find_db_instance(name, &db_inst));
-
-	*ldap_inst = db_inst->ldap_inst;
-
-cleanup:
-	return result;
-}
-
-static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
-find_db_instance(const char *name, db_instance_t **instance)
-{
-	db_instance_t *iterator;
-
-	REQUIRE(name != NULL);
-	REQUIRE(instance != NULL && *instance == NULL);
-
-	LOCK(&instance_list_lock);
-	iterator = HEAD(instance_list);
-	while (iterator != NULL) {
-		if (strcmp(name, iterator->name) == 0)
-			break;
-		iterator = NEXT(iterator, link);
-	}
-	UNLOCK(&instance_list_lock);
-
-	if (iterator != NULL) {
-		*instance = iterator;
-		return ISC_R_SUCCESS;
-	}
-
-	return ISC_R_NOTFOUND;
-}
-
-isc_result_t
-manager_get_db_timer(const char *name, isc_timer_t **timer) {
-	isc_result_t result;
-	db_instance_t *db_inst = NULL;
-
-	REQUIRE(name != NULL);
-
-	result = find_db_instance(name, &db_inst);
-	if (result == ISC_R_SUCCESS)
-		*timer = db_inst->timer;
-
-	return result;
-}
diff --git a/src/zone_manager.h b/src/zone_manager.h
deleted file mode 100644
index 1e06365..0000000
--- a/src/zone_manager.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009-2014  bind-dyndb-ldap authors; see COPYING for license
- */
-
-#ifndef _LD_ZONE_MANAGER_H_
-#define _LD_ZONE_MANAGER_H_
-
-#include <dns/types.h>
-
-#include "types.h"
-
-typedef struct db_instance db_instance_t;
-
-void destroy_manager(void);
-
-isc_result_t
-manager_create_db_instance(isc_mem_t *mctx, const char *name,
-			   const char * const *argv,
-			   dns_dyndb_arguments_t *dyndb_args) ATTR_NONNULLS ATTR_CHECKRESULT;
-
-isc_result_t
-manager_get_ldap_instance(const char *name,
-			  ldap_instance_t **ldap_inst) ATTR_NONNULLS ATTR_CHECKRESULT;
-
-isc_result_t
-manager_get_db_timer(const char *name,
-			  isc_timer_t **timer) ATTR_NONNULLS ATTR_CHECKRESULT;
-
-#endif /* !_LD_ZONE_MANAGER_H_ */
diff --git a/src/zone_register.c b/src/zone_register.c
index bde4a7c..d8525e9 100644
--- a/src/zone_register.c
+++ b/src/zone_register.c
@@ -260,15 +260,15 @@ cleanup:
 static isc_result_t ATTR_NONNULL(1,2,4,5,6,8)
 create_zone_info(isc_mem_t * const mctx, dns_zone_t * const raw,
 		dns_zone_t * const secure, const char * const dn,
-		 settings_set_t *global_settings, const char *db_name,
+		 settings_set_t *global_settings, ldap_instance_t *inst,
 		 dns_db_t * const ldapdb, zone_info_t **zinfop)
 {
 	isc_result_t result;
 	zone_info_t *zinfo;
 	char settings_name[PRINT_BUFF_SIZE];
 	ld_string_t *zone_dir = NULL;
-	char *argv[1];
 
+	REQUIRE(inst != NULL);
 	REQUIRE(raw != NULL);
 	REQUIRE(dn != NULL);
 	REQUIRE(zinfop != NULL && *zinfop == NULL);
@@ -294,11 +294,9 @@ create_zone_info(isc_mem_t * const mctx, dns_zone_t * const raw,
 	CHECK(fs_dirs_create(str_buf(zone_dir)));
 
 	if (ldapdb == NULL) { /* create new empty database */
-		DE_CONST(db_name, argv[0]);
 		CHECK(ldapdb_create(mctx, dns_zone_getorigin(raw),
 				    LDAP_DB_TYPE, LDAP_DB_RDATACLASS,
-				    sizeof(argv)/sizeof(argv[0]),
-				    argv, NULL, &zinfo->ldapdb));
+				    inst, &zinfo->ldapdb));
 	} else { /* re-use existing database */
 		dns_db_attach(ldapdb, &zinfo->ldapdb);
 	}
@@ -396,8 +394,7 @@ zr_add_zone(zone_register_t * const zr, dns_db_t * const ldapdb,
 	}
 
 	CHECK(create_zone_info(zr->mctx, raw, secure, dn, zr->global_settings,
-			       ldap_instance_getdbname(zr->ldap_inst), ldapdb,
-			       &new_zinfo));
+			       zr->ldap_inst, ldapdb, &new_zinfo));
 	CHECK(dns_rbt_addname(zr->rbt, name, new_zinfo));
 
 cleanup: