acl.c revision 28ad0be64ee756013c0f6a474fc447ee613ee0d1
/*
* Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.c,v 1.45 2008/04/29 01:01:42 each Exp $ */
/*! \file */
#include <config.h>
/*
* Create a new ACL, including an IP table and an array with room
* for 'n' ACL elements. The elements are uninitialized and the
* length is 0.
*/
/*
* Work around silly limitation of isc_mem_get().
*/
if (n == 0)
n = 1;
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS) {
return (result);
}
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Must set magic early because we use dns_acl_detach() to clean up.
*/
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
/*
* Create a new ACL and initialize it with the value "any" or "none",
* depending on the value of the "neg" parameter.
* "any" is a positive iptable entry with bit length 0.
* "none" is the same as "!any".
*/
static isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS) {
return (result);
}
return (result);
}
/*
* Create a new ACL that matches everything.
*/
}
/*
* Create a new ACL that matches nothing.
*/
}
/*
* If pos is ISC_TRUE, test whether acl is set to "{ any; }"
* If pos is ISC_FALSE, test whether acl is set to "{ none; }"
*/
static isc_boolean_t
{
/* Should never happen but let's be safe */
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE); /* All others */
}
/*
* Test whether acl is set to "{ any; }"
*/
{
}
/*
* Test whether acl is set to "{ none; }"
*/
{
}
/*
* Determine whether a given address or signer matches a given ACL.
* For a match with a positive ACL element or iptable radix entry,
* return with a positive value in match; for a match with a negated ACL
* element or radix entry, return with a negative value in match.
*/
const dns_name_t *reqsigner,
const dns_aclenv_t *env,
int *match,
const dns_aclelement_t **matchelt)
{
const isc_netaddr_t *addr;
int match_num = -1;
unsigned int i;
else {
}
/* Always match with host addresses. */
/* Assume no match. */
*match = 0;
/* Search radix. */
/* Found a match. */
else
}
/* Now search non-radix elements for a match with a lower node_num. */
/* Already found a better match? */
return (ISC_R_SUCCESS);
else
}
return (ISC_R_SUCCESS);
}
}
return (ISC_R_SUCCESS);
}
/*
* Merge the contents of one ACL into another. Call dns_iptable_merge()
* for the IP tables, then concatenate the element arrays.
*
* If pos is set to false, then the nested ACL is to be negated. This
* means reverse the sense of each *positive* element or IP table node,
* but leave negatives alone, so as to prevent a double-negative causing
* an unexpected postive match in the parent ACL.
*/
{
/* Resize the element array if needed. */
void *newmem;
if (newalloc < 4)
newalloc = 4;
newalloc * sizeof(dns_aclelement_t));
return (ISC_R_NOMEMORY);
/* Copy in the original elements */
/* Release the memory for the old elements array */
}
/*
* Now copy in the new elements, increasing their node_num
* values so as to keep the new ACL consistent. If we're
* negating, then negate positive elements, but keep negative
* elements the same for security reasons.
*/
/* Copy type. */
/* Adjust node numbering. */
/* Duplicate nested acl. */
/* Duplicate key name. */
if (result != ISC_R_SUCCESS)
return result;
}
/* reverse sense of positives if this is a negative acl */
} else {
}
}
/*
* Merge the iptables. Make sure the destination ACL's
* node_count value is set correctly afterward.
*/
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
/*
* Like dns_acl_match, but matches against the single ACL element 'e'
* rather than a complete ACL, and returns ISC_TRUE iff it matched.
*
* To determine whether the match was prositive or negative, the
* caller should examine e->negative. Since the element 'e' may be
* a reference to a named ACL or a nested ACL, a matching element
* returned through 'matchelt' is not necessarily 'e' itself.
*/
const dns_name_t *reqsigner,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
const dns_aclelement_t **matchelt)
{
int indirectmatch;
switch (e->type) {
*matchelt = e;
return (ISC_TRUE);
} else {
return (ISC_FALSE);
}
break;
return (ISC_FALSE);
break;
return (ISC_FALSE);
break;
default:
/* Should be impossible. */
INSIST(0);
}
/*
* Treat negative matches in indirect ACLs as "no match".
* That way, a negated indirect ACL will never become a
* surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0) {
*matchelt = e;
return (ISC_TRUE);
}
/*
* A negative indirect match may have set *matchelt, but we don't
* want it set when we return.
*/
return (ISC_FALSE);
}
void
}
static void
unsigned int i;
}
}
}
void
unsigned int refs;
if (refs == 0)
}
static isc_mutex_t insecure_prefix_lock;
static isc_boolean_t insecure_prefix_found;
static void
initialize_action(void) {
}
/*
* Called via isc_radix_walk() to find IP table nodes that are
* insecure.
*/
static void
/* Bitlen 0 means "any" or "none", which is always treated as IPv4 */
/* Negated entries are always secure. */
if (!secure) {
return;
}
/* If loopback prefix found, return */
switch (family) {
case AF_INET:
if (bitlen == 32 &&
return;
break;
case AF_INET6:
return;
break;
default:
break;
}
/* Non-negated, non-loopback */
return;
}
/*
* Return ISC_TRUE iff the acl 'a' is considered insecure, that is,
* if it contains IP addresses other than those of the local host.
* This is intended for applications such as printing warning
* messages for suspect ACLs; it is not intended for making access
* control decisions. We make no guarantee that an ACL for which
* this function returns ISC_FALSE is safe.
*/
dns_acl_isinsecure(const dns_acl_t *a) {
unsigned int i;
/*
* Walk radix tree to find out if there are any non-negated,
* non-loopback prefixes.
*/
if (insecure)
return(ISC_TRUE);
/* Now check non-radix elements */
for (i = 0; i < a->length; i++) {
dns_aclelement_t *e = &a->elements[i];
/* A negated match can never be insecure. */
if (e->negative)
continue;
switch (e->type) {
continue;
if (dns_acl_isinsecure(e->nestedacl))
return (ISC_TRUE);
continue;
return (ISC_TRUE);
default:
INSIST(0);
return (ISC_TRUE);
}
}
/* No insecure elements were found. */
return (ISC_FALSE);
}
/*
* Initialize ACL environment, setting up localhost and localnets ACLs
*/
if (result != ISC_R_SUCCESS)
goto cleanup_nothing;
if (result != ISC_R_SUCCESS)
goto cleanup_localhost;
return (ISC_R_SUCCESS);
return (result);
}
void
dns_acl_detach(&t->localhost);
dns_acl_detach(&t->localnets);
t->match_mapped = s->match_mapped;
}
void
}