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= -$ make - -Where 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 /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 " 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 "//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 " 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/") - 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: -/master//keys - - is described in section 5.1.3 of this file. - 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= + $ make + +Where `` 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 `/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 ` 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 "//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 ` 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/`) + + 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: + /master//keys + +`` is described in section 5.1.3 of this file. +`` 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 +#include 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 -#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 - -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 #include -#include +#include #include #include #include @@ -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 +#include +#include +#include #include +#include #include #include #include #include -#include +#include #include #include #include @@ -29,13 +33,12 @@ #include /* 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 +#include #include #include #include @@ -42,6 +42,7 @@ #include #include +#include #include #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 #include +#include #include @@ -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 #include #include + #include #include @@ -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 + +#include + #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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#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 - -#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: