Hello, the attached patch adds new attributes, idnsAllowQuery and idnsAllowTransfer, for the idnsZone. With those attributes it is now possible to set ACLs for the zone directly in LDAP.
Example of ACL setting: idnsAllowQuery: 127.0.0.1 idnsAllowQuery: ::1 idnsAllowQuery: 192.168.1.0/24 With this setting clients with 127.0.0.1 and ::1 IP addresses and clients from 192.168.1.0/24 network are allowed to obtain resource records from the zone. Comments are welcomed. Regards, Adam -- Adam Tkac, Red Hat, Inc.
>From bd14752e94a8d72d1c4d57167b3ad8e4be1e6e00 Mon Sep 17 00:00:00 2001 From: Adam Tkac <at...@redhat.com> Date: Mon, 10 Jan 2011 12:22:48 +0100 Subject: [PATCH] Add new idnsAllowQuery and idnsAllowTransfer zone attributes. The new attributes allows to set query and transfer ACLs for the zone. Signed-off-by: Adam Tkac <at...@redhat.com> --- README | 28 ++++++++++++ doc/schema | 14 ++++++- src/acl.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/acl.h | 17 +++++++ src/ldap_helper.c | 40 ++++++++++++----- src/ldap_helper.h | 9 ++++ 6 files changed, 218 insertions(+), 13 deletions(-) diff --git a/README b/README index 5c80344..66d198f 100644 --- a/README +++ b/README @@ -46,6 +46,34 @@ This will install the file ldap.so into the <libdir>/bind/ directory. You can find the complete LDAP schema in the documentation directory. An example zone ldif is available in the doc directory. +4.1 Zone (idnsZone) attributes +------------------------------ + +* idnsAllowQuery + Specifies BIND9 zone ACL element. This attribute can be set multiple + times and are merged together to the one ACL. + + Example: + idnsAllowQuery: 127.0.0.1 + idnsAllowQuery: ::1 + idnsAllowQuery: 192.168.1.0/24 + + In the example above clients with 127.0.0.1 and ::1 IP addresses and + clients from the 192.168.1.0/24 network are allowed to obtain records + from the zone. + + You can specify IPv4/IPv6 address, IPv4/IPv6 network address in CIDR + format and "any" or "none" keywords. The "!" prefix (for example + !192.168.1.0/24) 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. + 5. Configuration ================ diff --git a/doc/schema b/doc/schema index a5dacb4..b959f76 100644 --- a/doc/schema +++ b/doc/schema @@ -231,6 +231,18 @@ attributetype ( 2.16.840.1.113730.3.8.5.10 SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributetype ( 2.16.840.1.113730.3.8.5.11 + NAME 'idnsAllowQuery' + DESC 'BIND9 allow-query ACL element' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 2.16.840.1.113730.3.8.5.12 + NAME 'idnsAllowTransfer' + DESC 'BIND9 allow-transfer ACL element' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + objectclass ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' @@ -254,4 +266,4 @@ objectclass ( 2.16.840.1.113730.3.8.6.1 idnsSOAserial $ idnsSOArefresh $ idnsSOAretry $ idnsSOAexpire $ idnsSOAminimum ) - MAY idnsUpdatePolicy ) + MAY ( idnsUpdatePolicy $ idnsAllowQuery $ idnsAllowTransfer ) ) diff --git a/src/acl.c b/src/acl.c index ccd9ff4..07286f3 100644 --- a/src/acl.c +++ b/src/acl.c @@ -59,6 +59,7 @@ #include <string.h> #include <strings.h> +#include "acl.h" #include "str.h" #include "util.h" #include "log.h" @@ -393,3 +394,125 @@ acl_configure_zone_ssutable(const char *policy_str, dns_zone_t *zone) return result; } + +static isc_result_t +inaddr_fromtext(const char *addr, struct in_addr *in) +{ + if (inet_pton(AF_INET, addr, in) == 1) + return ISC_R_SUCCESS; + + return ISC_R_FAILURE; +} + +static isc_result_t +in6addr_fromtext(const char *addr, struct in6_addr *in6) +{ + if (inet_pton(AF_INET6, addr, in6) == 1) + return ISC_R_SUCCESS; + + return ISC_R_FAILURE; +} + +isc_result_t +acl_from_ldap(isc_mem_t *mctx, const ldap_value_list_t *vals, dns_acl_t **aclp) +{ + dns_acl_t *acl = NULL; + ldap_value_t *val; + int count = 0; + isc_result_t result = ISC_R_FAILURE; + + /* *aclp != NULL means nested ACL which is not allowed */ + REQUIRE(aclp != NULL && *aclp == NULL); + + CHECK(dns_acl_create(mctx, count, &acl)); + + /* Process ACL elements */ + for (val = HEAD(*vals); val != NULL; val = NEXT(val, link)) { + char *addr = val->value; + char *prefix; + isc_boolean_t neg = ISC_FALSE; + unsigned int bitlen; + struct in_addr in; + struct in6_addr in6; + isc_netaddr_t na; + + if (*addr == '!') { + neg = ISC_TRUE; + addr++; + acl->has_negatives = ISC_TRUE; + } + + if ((prefix = strchr(addr, '/')) != NULL) { + /* Net prefix */ + char *err; + + *prefix = '\0'; + prefix++; + + bitlen = strtol(prefix, &err, 10); + if (*err != '\0') { + log_error("Invalid network prefix"); + result = ISC_R_FAILURE; + goto cleanup; + } + + /* Convert IPv4/IPv6 address and add it to iptable */ + if (inaddr_fromtext(addr, &in) == ISC_R_SUCCESS) { + if (bitlen > 32) { + log_error("Too long network prefix"); + result = ISC_R_FAILURE; + goto cleanup; + } + isc_netaddr_fromin(&na, &in); + } else if (in6addr_fromtext(addr, &in6) == ISC_R_SUCCESS) { + if (bitlen > 128) { + log_error("Too long network prefix"); + result = ISC_R_FAILURE; + goto cleanup; + } + isc_netaddr_fromin6(&na, &in6); + } else { + log_error("Invalid network address"); + result = ISC_R_FAILURE; + goto cleanup; + } + + CHECK(dns_iptable_addprefix(acl->iptable, &na, bitlen, + !neg)); + } else { + /* It is IP address or "none" or "any" or invalid value */ + if (inaddr_fromtext(addr, &in) == ISC_R_SUCCESS) { + isc_netaddr_fromin(&na, &in); + bitlen = 32; + CHECK(dns_iptable_addprefix(acl->iptable, &na, bitlen, + !neg)); + } else if (in6addr_fromtext(addr, &in6) == ISC_R_SUCCESS) { + isc_netaddr_fromin6(&na, &in6); + bitlen = 128; + CHECK(dns_iptable_addprefix(acl->iptable, &na, bitlen, + !neg)); + } else if (strcasecmp(addr, "none") == 0) { + CHECK(dns_iptable_addprefix(acl->iptable, NULL, 0, + neg)); + } else if (strcasecmp(addr, "any") == 0) { + CHECK(dns_iptable_addprefix(acl->iptable, NULL, 0, + !neg)); + } else { + log_error("Invalid ACL element: %s", val->value); + result = ISC_R_FAILURE; + goto cleanup; + } + } + } + + *aclp = acl; + + return ISC_R_SUCCESS; + +cleanup: + if (acl != NULL) + dns_acl_detach(&acl); + + return result; +} + diff --git a/src/acl.h b/src/acl.h index 6298703..9933ac3 100644 --- a/src/acl.h +++ b/src/acl.h @@ -21,7 +21,24 @@ #ifndef _LD_ACL_H_ #define _LD_ACL_H_ +#include "ldap_helper.h" + +#include <dns/acl.h> + isc_result_t acl_configure_zone_ssutable(const char *policy_str, dns_zone_t *zone); +isc_result_t +acl_from_ldap(isc_mem_t *mctx, const ldap_value_list_t *vals, dns_acl_t **aclp); +/* + * Converts multiple ACL elements to the zone ACL. + * + * Allowed elements are: + * + * IPv4/IPv6 net prefix - 192.168.1.0/24 + * IPv4/IPv6 address - 192.168.1.1 + * any and none keywords + * "!" prefix means negation + */ + #endif /* !_LD_ACL_H_ */ diff --git a/src/ldap_helper.c b/src/ldap_helper.c index 9659b9d..f83cc30 100644 --- a/src/ldap_helper.c +++ b/src/ldap_helper.c @@ -82,10 +82,8 @@ typedef struct ldap_connection ldap_connection_t; typedef struct ldap_auth_pair ldap_auth_pair_t; typedef struct settings settings_t; -typedef struct ldap_value ldap_value_t; typedef struct ldap_attribute ldap_attribute_t; typedef struct ldap_entry ldap_entry_t; -typedef LIST(ldap_value_t) ldap_value_list_t; typedef LIST(ldap_attribute_t) ldap_attribute_list_t; typedef LIST(ldap_entry_t) ldap_entry_list_t; @@ -187,11 +185,6 @@ struct ldap_attribute { LINK(ldap_attribute_t) link; }; -struct ldap_value { - char *value; - LINK(ldap_value_t) link; -}; - /* * Constants. */ @@ -603,8 +596,9 @@ cleanup: return result; } +/* In BIND9 terminology "ssu" means "Simple Secure Update" */ static isc_result_t -modify_zone(dns_zone_t *zone, const char *update_str) +configure_zone_ssutable(dns_zone_t *zone, const char *update_str) { REQUIRE(zone != NULL); @@ -644,7 +638,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t create) int zone_count = 0; ldap_entry_t *entry; char *attrs[] = { - "idnsName", "idnsUpdatePolicy", NULL + "idnsName", "idnsUpdatePolicy", "idnsAllowQuery", + "idnsAllowTransfer", NULL }; REQUIRE(ldap_inst != NULL); @@ -686,13 +681,34 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t create) &name, &zone)); } - log_debug(2, "modifying zone %p: %s", zone, dn); + log_debug(2, "Setting SSU table for %p: %s", zone, dn); /* Get the update policy and update the zone with it. */ result = get_values(entry, "idnsUpdatePolicy", &values); if (result == ISC_R_SUCCESS) - CHECK_NEXT(modify_zone(zone, HEAD(values)->value)); + CHECK_NEXT(configure_zone_ssutable(zone, HEAD(values)->value)); else - CHECK_NEXT(modify_zone(zone, NULL)); + CHECK_NEXT(configure_zone_ssutable(zone, NULL)); + + /* Fetch allow-query and allow-transfer ACLs */ + log_debug(2, "Setting allow-query for %p: %s", zone, dn); + result = get_values(entry, "idnsAllowQuery", &values); + if (result == ISC_R_SUCCESS) { + dns_acl_t *queryacl = NULL; + CHECK_NEXT(acl_from_ldap(ldap_inst->mctx, &values, &queryacl)); + dns_zone_setqueryacl(zone, queryacl); + dns_acl_detach(&queryacl); + } else + log_debug(2, "allow-query not set"); + + log_debug(2, "Setting allow-transfer for %p: %s", zone, dn); + result = get_values(entry, "idnsAllowTransfer", &values); + if (result == ISC_R_SUCCESS) { + dns_acl_t *transferacl = NULL; + CHECK_NEXT(acl_from_ldap(ldap_inst->mctx, &values, &transferacl)); + dns_zone_setxfracl(zone, transferacl); + dns_acl_detach(&transferacl); + } else + log_debug(2, "allow-transfer not set"); zone_count++; next: diff --git a/src/ldap_helper.h b/src/ldap_helper.h index 7070556..594af43 100644 --- a/src/ldap_helper.h +++ b/src/ldap_helper.h @@ -22,10 +22,19 @@ #ifndef _LD_LDAP_HELPER_H_ #define _LD_LDAP_HELPER_H_ +#include "ldap_helper.h" + #include <isc/util.h> typedef struct ldap_instance ldap_instance_t; +typedef struct ldap_value ldap_value_t; +typedef LIST(ldap_value_t) ldap_value_list_t; +struct ldap_value { + char *value; + LINK(ldap_value_t) link; +}; + /* * some nice words about ldapdb_rdatalist_t: * - it is list of all RRs which have same owner name -- 1.7.3.4
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel