bind-dyndb-ldap/bind-9.11.patch
2016-11-21 16:40:19 +01:00

3216 lines
104 KiB
Diff

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: