void dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) { dns_acl_detach(&t->localhost); dns_acl_attach(s->localhost, &t->localhost); dns_acl_detach(&t->localnets); dns_acl_attach(s->localnets, &t->localnets); t->match_mapped = s->match_mapped; }
void dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) { dns_acl_detach(&t->localhost); dns_acl_attach(s->localhost, &t->localhost); dns_acl_detach(&t->localnets); dns_acl_attach(s->localnets, &t->localnets); t->match_mapped = s->match_mapped; #ifdef HAVE_GEOIP t->geoip_use_ecs = s->geoip_use_ecs; #endif }
static isc_result_t clearacl(isc_mem_t *mctx, dns_acl_t **aclp) { dns_acl_t *newacl = NULL; isc_result_t result; result = dns_acl_create(mctx, 0, &newacl); if (result != ISC_R_SUCCESS) return (result); dns_acl_detach(aclp); dns_acl_attach(newacl, aclp); dns_acl_detach(&newacl); return (ISC_R_SUCCESS); }
static void update_listener(ns_server_t *server, ns_statschannel_t **listenerp, const cfg_obj_t *listen_params, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext) { ns_statschannel_t *listener; const cfg_obj_t *allow = NULL; dns_acl_t *new_acl = NULL; isc_result_t result = ISC_R_SUCCESS; for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; listener = ISC_LIST_NEXT(listener, link)) if (isc_sockaddr_equal(addr, &listener->address)) break; if (listener == NULL) { *listenerp = NULL; return; } /* * Now, keep the old access list unless a new one can be made. */ allow = cfg_tuple_get(listen_params, "allow"); if (allow != NULL && cfg_obj_islist(allow)) { result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else result = dns_acl_any(listener->mctx, &new_acl); if (result == ISC_R_SUCCESS) { LOCK(&listener->lock); dns_acl_detach(&listener->acl); dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); UNLOCK(&listener->lock); } else { cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new acl for " "statistics channel %s: %s", socktext, isc_result_totext(result)); } *listenerp = listener; }
static void destroy(dns_acl_t *dacl) { unsigned int i; for (i = 0; i < dacl->length; i++) { dns_aclelement_t *de = &dacl->elements[i]; switch (de->type) { case dns_aclelementtype_keyname: dns_name_free(&de->u.keyname, dacl->mctx); break; case dns_aclelementtype_nestedacl: dns_acl_detach(&de->u.nestedacl); break; default: break; } } if (dacl->elements != NULL) isc_mem_put(dacl->mctx, dacl->elements, dacl->alloc * sizeof(dns_aclelement_t)); if (dacl->name != NULL) isc_mem_free(dacl->mctx, dacl->name); isc_refcount_destroy(&dacl->refcount); dacl->magic = 0; isc_mem_put(dacl->mctx, dacl, sizeof(*dacl)); }
static void destroy(dns_acl_t *dacl) { unsigned int i; INSIST(!ISC_LINK_LINKED(dacl, nextincache)); for (i = 0; i < dacl->length; i++) { dns_aclelement_t *de = &dacl->elements[i]; if (de->type == dns_aclelementtype_keyname) { dns_name_free(&de->keyname, dacl->mctx); } else if (de->type == dns_aclelementtype_nestedacl) { dns_acl_detach(&de->nestedacl); } } if (dacl->elements != NULL) isc_mem_put(dacl->mctx, dacl->elements, dacl->alloc * sizeof(dns_aclelement_t)); if (dacl->name != NULL) isc_mem_free(dacl->mctx, dacl->name); if (dacl->iptable != NULL) dns_iptable_detach(&dacl->iptable); isc_refcount_destroy(&dacl->refcount); dacl->magic = 0; isc_mem_put(dacl->mctx, dacl, sizeof(*dacl)); }
void cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp) { cfg_aclconfctx_t *actx; dns_acl_t *dacl, *next; unsigned int refs; REQUIRE(actxp != NULL && *actxp != NULL); actx = *actxp; isc_refcount_decrement(&actx->references, &refs); if (refs == 0) { for (dacl = ISC_LIST_HEAD(actx->named_acl_cache); dacl != NULL; dacl = next) { next = ISC_LIST_NEXT(dacl, nextincache); ISC_LIST_UNLINK(actx->named_acl_cache, dacl, nextincache); dns_acl_detach(&dacl); } isc_mem_putanddetach(&actx->mctx, actx, sizeof(*actx)); } *actxp = NULL; }
/* * 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. */ isc_result_t dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) { isc_result_t result; dns_acl_t *acl; /* * Work around silly limitation of isc_mem_get(). */ if (n == 0) n = 1; acl = isc_mem_get(mctx, sizeof(*acl)); if (acl == NULL) return (ISC_R_NOMEMORY); acl->mctx = NULL; isc_mem_attach(mctx, &acl->mctx); acl->name = NULL; result = isc_refcount_init(&acl->refcount, 1); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, acl, sizeof(*acl)); return (result); } result = dns_iptable_create(mctx, &acl->iptable); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, acl, sizeof(*acl)); return (result); } acl->elements = NULL; acl->alloc = 0; acl->length = 0; acl->has_negatives = ISC_FALSE; ISC_LINK_INIT(acl, nextincache); /* * Must set magic early because we use dns_acl_detach() to clean up. */ acl->magic = DNS_ACL_MAGIC; acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t)); if (acl->elements == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } acl->alloc = n; memset(acl->elements, 0, n * sizeof(dns_aclelement_t)); *target = acl; return (ISC_R_SUCCESS); cleanup: dns_acl_detach(&acl); return (result); }
void ns_aclconfctx_destroy(ns_aclconfctx_t *ctx) { dns_acl_t *dacl, *next; for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); dacl != NULL; dacl = next) { next = ISC_LIST_NEXT(dacl, nextincache); dns_acl_detach(&dacl); } }
static void destroy_listener(void *arg) { ns_statschannel_t *listener = arg; REQUIRE(listener != NULL); REQUIRE(!ISC_LINK_LINKED(listener, link)); /* We don't have to acquire the lock here since it's already unlinked */ dns_acl_detach(&listener->acl); DESTROYLOCK(&listener->lock); isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); }
static void free_listener(controllistener_t *listener) { INSIST(listener->exiting); INSIST(!listener->listening); INSIST(ISC_LIST_EMPTY(listener->connections)); if (listener->sock != NULL) isc_socket_detach(&listener->sock); free_controlkeylist(&listener->keys, listener->mctx); if (listener->acl != NULL) dns_acl_detach(&listener->acl); isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); }
/* * 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 dns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) { isc_result_t result; dns_acl_t *acl = NULL; result = dns_acl_create(mctx, 0, &acl); if (result != ISC_R_SUCCESS) return (result); result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg)); if (result != ISC_R_SUCCESS) { dns_acl_detach(&acl); return (result); } *target = acl; return (result); }
isc_result_t dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) { isc_result_t result; env->localhost = NULL; env->localnets = NULL; result = dns_acl_create(mctx, 0, &env->localhost); if (result != ISC_R_SUCCESS) goto cleanup_nothing; result = dns_acl_create(mctx, 0, &env->localnets); if (result != ISC_R_SUCCESS) goto cleanup_localhost; env->match_mapped = ISC_FALSE; return (ISC_R_SUCCESS); cleanup_localhost: dns_acl_detach(&env->localhost); cleanup_nothing: return (result); }
isc_result_t ns_listenlist_default (isc_mem_t * mctx, in_port_t port, isc_boolean_t enabled, ns_listenlist_t ** target) { isc_result_t result; dns_acl_t *acl = NULL; ns_listenelt_t *elt = NULL; ns_listenlist_t *list = NULL; REQUIRE (target != NULL && *target == NULL); if (enabled) result = dns_acl_any (mctx, &acl); else result = dns_acl_none (mctx, &acl); if (result != ISC_R_SUCCESS) goto cleanup; result = ns_listenelt_create (mctx, port, acl, &elt); if (result != ISC_R_SUCCESS) goto cleanup_acl; result = ns_listenlist_create (mctx, &list); if (result != ISC_R_SUCCESS) goto cleanup_listenelt; ISC_LIST_APPEND (list->elts, elt, link); *target = list; return (ISC_R_SUCCESS); cleanup_listenelt: ns_listenelt_destroy (elt); cleanup_acl: dns_acl_detach (&acl); cleanup: return (result); }
void dns_dampening_destroy(dns_view_t * view) { int i, num_workers = sizeof(implementations)/sizeof(*implementations); INSIST( view != NULL ); INSIST( view->dampening != NULL ); if(view->dampening->exempt != NULL) dns_acl_detach(&view->dampening->exempt); for( i = view->dampening->workers_count; i-- > 0; ) { DESTROYLOCK(&view->dampening->workers[i].lock); view->dampening->workers[i].destroy(&(view->dampening->workers[i].data)); } view->dampening->workers_count = 0; isc_mem_put(view->mctx, view->dampening->workers, num_workers * sizeof(*(view->dampening->workers))); view->dampening->workers = NULL; isc_mem_put(view->mctx, view->dampening, sizeof(*(view->dampening))); view->dampening = NULL; INSIST( view->dampening == NULL ); }
static isc_result_t add_listener(ns_server_t *server, ns_statschannel_t **listenerp, const cfg_obj_t *listen_params, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext) { isc_result_t result; ns_statschannel_t *listener; isc_task_t *task = NULL; isc_socket_t *sock = NULL; const cfg_obj_t *allow; dns_acl_t *new_acl = NULL; listener = isc_mem_get(server->mctx, sizeof(*listener)); if (listener == NULL) return (ISC_R_NOMEMORY); listener->httpdmgr = NULL; listener->address = *addr; listener->acl = NULL; listener->mctx = NULL; ISC_LINK_INIT(listener, link); result = isc_mutex_init(&listener->lock); if (result != ISC_R_SUCCESS) { isc_mem_put(server->mctx, listener, sizeof(*listener)); return (ISC_R_FAILURE); } isc_mem_attach(server->mctx, &listener->mctx); allow = cfg_tuple_get(listen_params, "allow"); if (allow != NULL && cfg_obj_islist(allow)) { result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else result = dns_acl_any(listener->mctx, &new_acl); if (result != ISC_R_SUCCESS) goto cleanup; dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); result = isc_task_create(ns_g_taskmgr, 0, &task); if (result != ISC_R_SUCCESS) goto cleanup; isc_task_setname(task, "statchannel", NULL); result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr), isc_sockettype_tcp, &sock); if (result != ISC_R_SUCCESS) goto cleanup; isc_socket_setname(sock, "statchannel", NULL); #ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(sock, ISC_TRUE); #endif result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, destroy_listener, listener, ns_g_timermgr, &listener->httpdmgr); if (result != ISC_R_SUCCESS) goto cleanup; #ifdef HAVE_LIBXML2 isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server); #endif isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl, server); *listenerp = listener; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_NOTICE, "statistics channel listening on %s", socktext); cleanup: if (result != ISC_R_SUCCESS) { if (listener->acl != NULL) dns_acl_detach(&listener->acl); DESTROYLOCK(&listener->lock); isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); } if (task != NULL) isc_task_detach(&task); if (sock != NULL) isc_socket_detach(&sock); return (result); }
/* * Recursively pre-parse an ACL definition to find the total number * of non-IP-prefix elements (localhost, localnets, key) in all nested * ACLs, so that the parent will have enough space allocated for the * elements table after all the nested ACLs have been merged in to the * parent. */ static isc_result_t count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, isc_uint32_t *count, isc_boolean_t *has_negative) { const cfg_listelt_t *elt; isc_result_t result; isc_uint32_t n = 0; REQUIRE(count != NULL); if (has_negative != NULL) *has_negative = ISC_FALSE; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); /* might be a negated element, in which case get the value. */ if (cfg_obj_istuple(ce)) { const cfg_obj_t *negated = cfg_tuple_get(ce, "negated"); if (! cfg_obj_isvoid(negated)) { ce = negated; if (has_negative != NULL) *has_negative = ISC_TRUE; } } if (cfg_obj_istype(ce, &cfg_type_keyref)) { n++; } else if (cfg_obj_islist(ce)) { isc_boolean_t negative; isc_uint32_t sub; result = count_acl_elements(ce, cctx, lctx, ctx, mctx, &sub, &negative); if (result != ISC_R_SUCCESS) return (result); n += sub; if (negative) n++; #ifdef HAVE_GEOIP } else if (cfg_obj_istuple(ce) && cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) { n++; #endif /* HAVE_GEOIP */ } else if (cfg_obj_isstring(ce)) { const char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "localhost") == 0 || strcasecmp(name, "localnets") == 0 || strcasecmp(name, "none") == 0) { n++; } else if (strcasecmp(name, "any") != 0) { dns_acl_t *inneracl = NULL; /* * Convert any named acls we reference now if * they have not already been converted. */ result = convert_named_acl(ce, cctx, lctx, ctx, mctx, 0, &inneracl); if (result == ISC_R_SUCCESS) { if (inneracl->has_negatives) n++; else n += inneracl->length; dns_acl_detach(&inneracl); } else return (result); } } } *count = n; return (ISC_R_SUCCESS); }
static void update_listener(ns_controls_t *cp, controllistener_t **listenerp, const cfg_obj_t *control, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext, isc_sockettype_t type) { controllistener_t *listener; const cfg_obj_t *allow; const cfg_obj_t *global_keylist = NULL; const cfg_obj_t *control_keylist = NULL; dns_acl_t *new_acl = NULL; controlkeylist_t keys; isc_result_t result = ISC_R_SUCCESS; for (listener = ISC_LIST_HEAD(cp->listeners); listener != NULL; listener = ISC_LIST_NEXT(listener, link)) if (isc_sockaddr_equal(addr, &listener->address)) break; if (listener == NULL) { *listenerp = NULL; return; } /* * There is already a listener for this sockaddr. * Update the access list and key information. * * First try to deal with the key situation. There are a few * possibilities: * (a) It had an explicit keylist and still has an explicit keylist. * (b) It had an automagic key and now has an explicit keylist. * (c) It had an explicit keylist and now needs an automagic key. * (d) It has an automagic key and still needs the automagic key. * * (c) and (d) are the annoying ones. The caller needs to know * that it should use the automagic configuration for key information * in place of the named.conf configuration. * * XXXDCL There is one other hazard that has not been dealt with, * the problem that if a key change is being caused by a control * channel reload, then the response will be with the new key * and not able to be decrypted by the client. */ if (control != NULL) get_key_info(config, control, &global_keylist, &control_keylist); if (control_keylist != NULL) { INSIST(global_keylist != NULL); ISC_LIST_INIT(keys); result = controlkeylist_fromcfg(control_keylist, listener->mctx, &keys); if (result == ISC_R_SUCCESS) { free_controlkeylist(&listener->keys, listener->mctx); listener->keys = keys; register_keys(control, global_keylist, &listener->keys, listener->mctx, socktext); } } else { free_controlkeylist(&listener->keys, listener->mctx); result = get_rndckey(listener->mctx, &listener->keys); } if (result != ISC_R_SUCCESS && global_keylist != NULL) { /* * This message might be a little misleading since the * "new keys" might in fact be identical to the old ones, * but tracking whether they are identical just for the * sake of avoiding this message would be too much trouble. */ if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new keys for " "command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, "couldn't install new keys for " "command channel %s: %s", socktext, isc_result_totext(result)); } /* * Now, keep the old access list unless a new one can be made. */ if (control != NULL && type == isc_sockettype_tcp) { allow = cfg_tuple_get(control, "allow"); result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else { result = dns_acl_any(listener->mctx, &new_acl); } if (result == ISC_R_SUCCESS) { dns_acl_detach(&listener->acl); dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); /* XXXDCL say the old acl is still used? */ } else if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new acl for " "command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, "couldn't install new acl for " "command channel %s: %s", socktext, isc_result_totext(result)); if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { isc_uint32_t perm, owner, group; perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); result = ISC_R_SUCCESS; if (listener->perm != perm || listener->owner != owner || listener->group != group) result = isc_socket_permunix(&listener->address, perm, owner, group); if (result == ISC_R_SUCCESS) { listener->perm = perm; listener->owner = owner; listener->group = group; } else if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't update ownership/permission for " "command channel %s", socktext); } *listenerp = listener; }
void dns_aclenv_destroy(dns_aclenv_t *env) { dns_acl_detach(&env->localhost); dns_acl_detach(&env->localnets); }
static void add_listener(ns_controls_t *cp, controllistener_t **listenerp, const cfg_obj_t *control, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext, isc_sockettype_t type) { isc_mem_t *mctx = cp->server->mctx; controllistener_t *listener; const cfg_obj_t *allow; const cfg_obj_t *global_keylist = NULL; const cfg_obj_t *control_keylist = NULL; dns_acl_t *new_acl = NULL; isc_result_t result = ISC_R_SUCCESS; listener = isc_mem_get(mctx, sizeof(*listener)); if (listener == NULL) result = ISC_R_NOMEMORY; if (result == ISC_R_SUCCESS) { listener->mctx = NULL; isc_mem_attach(mctx, &listener->mctx); listener->controls = cp; listener->task = cp->server->task; listener->address = *addr; listener->sock = NULL; listener->listening = ISC_FALSE; listener->exiting = ISC_FALSE; listener->acl = NULL; listener->type = type; listener->perm = 0; listener->owner = 0; listener->group = 0; ISC_LINK_INIT(listener, link); ISC_LIST_INIT(listener->keys); ISC_LIST_INIT(listener->connections); /* * Make the acl. */ if (control != NULL && type == isc_sockettype_tcp) { allow = cfg_tuple_get(control, "allow"); result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, mctx, 0, &new_acl); } else { result = dns_acl_any(mctx, &new_acl); } } if (result == ISC_R_SUCCESS) { dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); if (config != NULL) get_key_info(config, control, &global_keylist, &control_keylist); if (control_keylist != NULL) { result = controlkeylist_fromcfg(control_keylist, listener->mctx, &listener->keys); if (result == ISC_R_SUCCESS) register_keys(control, global_keylist, &listener->keys, listener->mctx, socktext); } else result = get_rndckey(mctx, &listener->keys); if (result != ISC_R_SUCCESS && control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install keys for " "command channel %s: %s", socktext, isc_result_totext(result)); } if (result == ISC_R_SUCCESS) { int pf = isc_sockaddr_pf(&listener->address); if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || #ifdef ISC_PLATFORM_HAVESYSUNH (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || #endif (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) result = ISC_R_FAMILYNOSUPPORT; } if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) isc_socket_cleanunix(&listener->address, ISC_FALSE); if (result == ISC_R_SUCCESS) result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(&listener->address), type, &listener->sock); if (result == ISC_R_SUCCESS) isc_socket_setname(listener->sock, "control", NULL); #ifndef ISC_ALLOW_MAPPED if (result == ISC_R_SUCCESS) isc_socket_ipv6only(listener->sock, ISC_TRUE); #endif if (result == ISC_R_SUCCESS) result = isc_socket_bind(listener->sock, &listener->address, ISC_SOCKET_REUSEADDRESS); if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); listener->group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); result = isc_socket_permunix(&listener->address, listener->perm, listener->owner, listener->group); } if (result == ISC_R_SUCCESS) result = control_listen(listener); if (result == ISC_R_SUCCESS) result = control_accept(listener); if (result == ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "command channel listening on %s", socktext); *listenerp = listener; } else { if (listener != NULL) { listener->exiting = ISC_TRUE; free_listener(listener); } if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); *listenerp = NULL; } /* XXXDCL return error results? fail hard? */ }
isc_result_t cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, unsigned int nest_level, isc_uint16_t family, dns_acl_t **target) { isc_result_t result; dns_acl_t *dacl = NULL, *inneracl = NULL; dns_aclelement_t *de; const cfg_listelt_t *elt; dns_iptable_t *iptab; int new_nest_level = 0; if (nest_level != 0) new_nest_level = nest_level - 1; REQUIRE(target != NULL); REQUIRE(*target == NULL || DNS_ACL_VALID(*target)); if (*target != NULL) { /* * If target already points to an ACL, then we're being * called recursively to configure a nested ACL. The * nested ACL's contents should just be absorbed into its * parent ACL. */ dns_acl_attach(*target, &dacl); dns_acl_detach(target); } else { /* * Need to allocate a new ACL structure. Count the items * in the ACL definition that will require space in the * elements table. (Note that if nest_level is nonzero, * *everything* goes in the elements table.) */ isc_uint32_t nelem; if (nest_level == 0) { result = count_acl_elements(caml, cctx, lctx, ctx, mctx, &nelem, NULL); if (result != ISC_R_SUCCESS) return (result); } else nelem = cfg_list_length(caml, ISC_FALSE); result = dns_acl_create(mctx, nelem, &dacl); if (result != ISC_R_SUCCESS) return (result); } de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); isc_boolean_t neg = ISC_FALSE; INSIST(dacl->length <= dacl->alloc); if (cfg_obj_istuple(ce)) { /* Might be a negated element */ const cfg_obj_t *negated = cfg_tuple_get(ce, "negated"); if (! cfg_obj_isvoid(negated)) { neg = ISC_TRUE; dacl->has_negatives = ISC_TRUE; ce = negated; } } /* * If nest_level is nonzero, then every element is * to be stored as a separate, nested ACL rather than * merged into the main iptable. */ iptab = dacl->iptable; if (nest_level != 0) { result = dns_acl_create(mctx, cfg_list_length(ce, ISC_FALSE), &de->nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; iptab = de->nestedacl->iptable; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ isc_netaddr_t addr; unsigned int bitlen; cfg_obj_asnetprefix(ce, &addr, &bitlen); if (family != 0 && family != addr.family) { char buf[ISC_NETADDR_FORMATSIZE + 1]; isc_netaddr_format(&addr, buf, sizeof(buf)); cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "'%s': incorrect address family; " "ignoring", buf); if (nest_level != 0) dns_acl_detach(&de->nestedacl); continue; } result = isc_netaddr_prefixok(&addr, bitlen); if (result != ISC_R_SUCCESS) { char buf[ISC_NETADDR_FORMATSIZE + 1]; isc_netaddr_format(&addr, buf, sizeof(buf)); cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "'%s/%u': address/prefix length " "mismatch", buf, bitlen); } /* * If nesting ACLs (nest_level != 0), we negate * the nestedacl element, not the iptable entry. */ result = dns_iptable_addprefix(iptab, &addr, bitlen, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level > 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (cfg_obj_islist(ce)) { /* * If we're nesting ACLs, put the nested * ACL onto the elements list; otherwise * merge it into *this* ACL. We nest ACLs * in two cases: 1) sortlist, 2) if the * nested ACL contains negated members. */ if (inneracl != NULL) dns_acl_detach(&inneracl); result = cfg_acl_fromconfig(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; nested_acl: if (nest_level > 0 || inneracl->has_negatives) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; if (de->nestedacl != NULL) dns_acl_detach(&de->nestedacl); dns_acl_attach(inneracl, &de->nestedacl); dns_acl_detach(&inneracl); /* Fall through. */ } else { INSIST(dacl->length + inneracl->length <= dacl->alloc); dns_acl_merge(dacl, inneracl, ISC_TF(!neg)); de += inneracl->length; /* elements added */ dns_acl_detach(&inneracl); INSIST(dacl->length <= dacl->alloc); continue; } } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name. */ INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_keyname; de->negative = neg; dns_name_init(&de->keyname, NULL); result = convert_keyname(ce, lctx, mctx, &de->keyname); if (result != ISC_R_SUCCESS) goto cleanup; #ifdef HAVE_GEOIP } else if (cfg_obj_istuple(ce) && cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) { INSIST(dacl->length < dacl->alloc); result = parse_geoip_element(ce, lctx, ctx, de); if (result != ISC_R_SUCCESS) goto cleanup; de->type = dns_aclelementtype_geoip; de->negative = neg; #endif /* HAVE_GEOIP */ } else if (cfg_obj_isstring(ce)) { /* ACL name. */ const char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "any") == 0) { /* Iptable entry with zero bit length. */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level != 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (strcasecmp(name, "none") == 0) { /* none == !any */ /* * We don't unconditional set * dacl->has_negatives and * de->negative to true so we can handle * "!none;". */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (!neg) dacl->has_negatives = !neg; if (nest_level != 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = !neg; } else continue; } else if (strcasecmp(name, "localhost") == 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_localhost; de->negative = neg; } else if (strcasecmp(name, "localnets") == 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_localnets; de->negative = neg; } else { if (inneracl != NULL) dns_acl_detach(&inneracl); /* * This call should just find the cached * of the named acl. */ result = convert_named_acl(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; goto nested_acl; } } else { cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } /* * This should only be reached for localhost, localnets * and keyname elements, and nested ACLs if nest_level is * nonzero (i.e., in sortlists). */ if (de->nestedacl != NULL && de->type != dns_aclelementtype_nestedacl) dns_acl_detach(&de->nestedacl); dacl->node_count++; de->node_num = dacl->node_count; dacl->length++; de++; INSIST(dacl->length <= dacl->alloc); } dns_acl_attach(dacl, target); result = ISC_R_SUCCESS; cleanup: if (inneracl != NULL) dns_acl_detach(&inneracl); dns_acl_detach(&dacl); return (result); }
isc_result_t ns_acl_fromconfig(cfg_obj_t *caml, cfg_obj_t *cctx, ns_aclconfctx_t *ctx, isc_mem_t *mctx, dns_acl_t **target) { isc_result_t result; unsigned int count; dns_acl_t *dacl = NULL; dns_aclelement_t *de; cfg_listelt_t *elt; REQUIRE(target != NULL && *target == NULL); count = 0; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) count++; result = dns_acl_create(mctx, count, &dacl); if (result != ISC_R_SUCCESS) return (result); de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { cfg_obj_t *ce = cfg_listelt_value(elt); if (cfg_obj_istuple(ce)) { /* This must be a negated element. */ ce = cfg_tuple_get(ce, "value"); de->negative = ISC_TRUE; } else { de->negative = ISC_FALSE; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ de->type = dns_aclelementtype_ipprefix; cfg_obj_asnetprefix(ce, &de->u.ip_prefix.address, &de->u.ip_prefix.prefixlen); } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name */ de->type = dns_aclelementtype_keyname; dns_name_init(&de->u.keyname, NULL); result = convert_keyname(ce, mctx, &de->u.keyname); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_islist(ce)) { /* Nested ACL */ de->type = dns_aclelementtype_nestedacl; result = ns_acl_fromconfig(ce, cctx, ctx, mctx, &de->u.nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_isstring(ce)) { /* ACL name */ char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "localhost") == 0) { de->type = dns_aclelementtype_localhost; } else if (strcasecmp(name, "localnets") == 0) { de->type = dns_aclelementtype_localnets; } else if (strcasecmp(name, "any") == 0) { de->type = dns_aclelementtype_any; } else if (strcasecmp(name, "none") == 0) { de->type = dns_aclelementtype_any; de->negative = ISC_TF(! de->negative); } else { de->type = dns_aclelementtype_nestedacl; result = convert_named_acl(ce, cctx, ctx, mctx, &de->u.nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; } } else { cfg_obj_log(ce, dns_lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } de++; dacl->length++; } *target = dacl; return (ISC_R_SUCCESS); cleanup: dns_acl_detach(&dacl); return (result); }
void ns_listenelt_destroy (ns_listenelt_t * elt) { if (elt->acl != NULL) dns_acl_detach (&elt->acl); isc_mem_put (elt->mctx, elt, sizeof (*elt)); }
isc_result_t cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, unsigned int nest_level, dns_acl_t **target) { isc_result_t result; dns_acl_t *dacl = NULL, *inneracl = NULL; dns_aclelement_t *de; const cfg_listelt_t *elt; dns_iptable_t *iptab; int new_nest_level = 0; if (nest_level != 0) new_nest_level = nest_level - 1; REQUIRE(target != NULL); REQUIRE(*target == NULL || DNS_ACL_VALID(*target)); if (*target != NULL) { /* * If target already points to an ACL, then we're being * called recursively to configure a nested ACL. The * nested ACL's contents should just be absorbed into its * parent ACL. */ dns_acl_attach(*target, &dacl); dns_acl_detach(target); } else { /* * Need to allocate a new ACL structure. Count the items * in the ACL definition that will require space in the * elements table. (Note that if nest_level is nonzero, * *everything* goes in the elements table.) */ int nelem; if (nest_level == 0) nelem = count_acl_elements(caml, cctx, NULL); else nelem = cfg_list_length(caml, ISC_FALSE); result = dns_acl_create(mctx, nelem, &dacl); if (result != ISC_R_SUCCESS) return (result); } de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); isc_boolean_t neg; if (cfg_obj_istuple(ce)) { /* This must be a negated element. */ ce = cfg_tuple_get(ce, "value"); neg = ISC_TRUE; dacl->has_negatives = ISC_TRUE; } else neg = ISC_FALSE; /* * If nest_level is nonzero, then every element is * to be stored as a separate, nested ACL rather than * merged into the main iptable. */ iptab = dacl->iptable; if (nest_level != 0) { result = dns_acl_create(mctx, cfg_list_length(ce, ISC_FALSE), &de->nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; iptab = de->nestedacl->iptable; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ isc_netaddr_t addr; unsigned int bitlen; cfg_obj_asnetprefix(ce, &addr, &bitlen); /* * If nesting ACLs (nest_level != 0), we negate * the nestedacl element, not the iptable entry. */ result = dns_iptable_addprefix(iptab, &addr, bitlen, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level > 0) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (cfg_obj_islist(ce)) { /* * If we're nesting ACLs, put the nested * ACL onto the elements list; otherwise * merge it into *this* ACL. We nest ACLs * in two cases: 1) sortlist, 2) if the * nested ACL contains negated members. */ if (inneracl != NULL) dns_acl_detach(&inneracl); result = cfg_acl_fromconfig(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; nested_acl: if (nest_level > 0 || inneracl->has_negatives) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; if (de->nestedacl != NULL) dns_acl_detach(&de->nestedacl); dns_acl_attach(inneracl, &de->nestedacl); dns_acl_detach(&inneracl); /* Fall through. */ } else { dns_acl_merge(dacl, inneracl, ISC_TF(!neg)); de += inneracl->length; /* elements added */ dns_acl_detach(&inneracl); continue; } } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name. */ de->type = dns_aclelementtype_keyname; de->negative = neg; dns_name_init(&de->keyname, NULL); result = convert_keyname(ce, lctx, mctx, &de->keyname); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_isstring(ce)) { /* ACL name. */ const char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "any") == 0) { /* Iptable entry with zero bit length. */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level != 0) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (strcasecmp(name, "none") == 0) { /* none == !any */ /* * We don't unconditional set * dacl->has_negatives and * de->negative to true so we can handle * "!none;". */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (!neg) dacl->has_negatives = !neg; if (nest_level != 0) { de->type = dns_aclelementtype_nestedacl; de->negative = !neg; } else continue; #ifdef SUPPORT_GEOIP } else if ((0 == (strncmp("country_", name, 8))) && (10 == strlen(name))) { /* It is a country code */ de->type = dns_aclelementtype_ipcountry; de->country[0] = name[8]; de->country[1] = name[9]; de->country[2] = '\0'; #endif } else if (strcasecmp(name, "localhost") == 0) { de->type = dns_aclelementtype_localhost; de->negative = neg; } else if (strcasecmp(name, "localnets") == 0) { de->type = dns_aclelementtype_localnets; de->negative = neg; } else { if (inneracl != NULL) dns_acl_detach(&inneracl); result = convert_named_acl(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; goto nested_acl; } } else { cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } /* * This should only be reached for localhost, localnets * and keyname elements, and nested ACLs if nest_level is * nonzero (i.e., in sortlists). */ if (de->nestedacl != NULL && de->type != dns_aclelementtype_nestedacl) dns_acl_detach(&de->nestedacl); dacl->node_count++; de->node_num = dacl->node_count; dacl->length++; de++; INSIST(dacl->length <= dacl->alloc); } dns_acl_attach(dacl, target); result = ISC_R_SUCCESS; cleanup: if (inneracl != NULL) dns_acl_detach(&inneracl); dns_acl_detach(&dacl); return (result); }
/*% * Convenience function for configuring a single zone ACL. */ static isc_result_t configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, const cfg_obj_t *config, acl_type_t acltype, cfg_aclconfctx_t *actx, dns_zone_t *zone, void (*setzacl)(dns_zone_t *, dns_acl_t *), void (*clearzacl)(dns_zone_t *)) { isc_result_t result; const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL}; const cfg_obj_t *aclobj = NULL; int i = 0; dns_acl_t **aclp = NULL, *acl = NULL; const char *aclname; dns_view_t *view; view = dns_zone_getview(zone); switch (acltype) { case allow_notify: if (view != NULL) aclp = &view->notifyacl; aclname = "allow-notify"; break; case allow_query: if (view != NULL) aclp = &view->queryacl; aclname = "allow-query"; break; case allow_transfer: if (view != NULL) aclp = &view->transferacl; aclname = "allow-transfer"; break; case allow_update: if (view != NULL) aclp = &view->updateacl; aclname = "allow-update"; break; case allow_update_forwarding: if (view != NULL) aclp = &view->upfwdacl; aclname = "allow-update-forwarding"; break; default: INSIST(0); return (ISC_R_FAILURE); } /* First check to see if ACL is defined within the zone */ if (zconfig != NULL) { maps[0] = cfg_tuple_get(zconfig, "options"); (void)ns_config_get(maps, aclname, &aclobj); if (aclobj != NULL) { aclp = NULL; goto parse_acl; } } /* Failing that, see if there's a default ACL already in the view */ if (aclp != NULL && *aclp != NULL) { (*setzacl)(zone, *aclp); return (ISC_R_SUCCESS); } /* Check for default ACLs that haven't been parsed yet */ if (vconfig != NULL) { const cfg_obj_t *options = cfg_tuple_get(vconfig, "options"); if (options != NULL) maps[i++] = options; } if (config != NULL) { const cfg_obj_t *options = NULL; (void)cfg_map_get(config, "options", &options); if (options != NULL) maps[i++] = options; } maps[i++] = ns_g_defaults; maps[i] = NULL; (void)ns_config_get(maps, aclname, &aclobj); if (aclobj == NULL) { (*clearzacl)(zone); return (ISC_R_SUCCESS); } parse_acl: result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx, dns_zone_getmctx(zone), 0, &acl); if (result != ISC_R_SUCCESS) return (result); (*setzacl)(zone, acl); /* Set the view default now */ if (aclp != NULL) dns_acl_attach(acl, aclp); dns_acl_detach(&acl); return (ISC_R_SUCCESS); }