diff options
Diffstat (limited to 'contrib/bind/bin/named/db_sec.c')
-rw-r--r-- | contrib/bind/bin/named/db_sec.c | 1081 |
1 files changed, 0 insertions, 1081 deletions
diff --git a/contrib/bind/bin/named/db_sec.c b/contrib/bind/bin/named/db_sec.c deleted file mode 100644 index 5e03fb9..0000000 --- a/contrib/bind/bin/named/db_sec.c +++ /dev/null @@ -1,1081 +0,0 @@ - -#if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: db_sec.c,v 8.36 2002/11/17 14:51:50 marka Exp $"; -#endif /* not lint */ - -/* - * Copyright (c) 1986, 1990 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION 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. - */ - -/* - * Portions Copyright (c) 1996-2000 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM 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. - */ - -#include "port_before.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <arpa/nameser.h> - -#include <ctype.h> -#include <resolv.h> -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <time.h> - -#include <isc/eventlib.h> -#include <isc/logging.h> -#include <isc/memcluster.h> -#include <isc/tree.h> - -#include <isc/dst.h> - -#include "port_after.h" - -#include "named.h" - -struct zpubkey { - struct dst_key *zpk_key; /* Should be DST_KEY */ - char *zpk_name; - struct zpubkey *zpk_next; -}; - -typedef struct zpubkey *zpubkey_list; - -static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset); - -/* - * A converted databuf is a stripped down databuf after converting the - * data to wire format. - */ -struct converted_databuf { - struct converted_databuf *cd_next; - u_char *cd_data; - int cd_size, cd_alloc; -}; - -/* All of the trusted keys and zone keys */ -static tree *trusted_keys = NULL; - -static int -compare_pubkey (struct zpubkey *zpk1, struct zpubkey *zpk2) { - char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; - - if (ns_makecanon(zpk1->zpk_name, ta, sizeof ta) < 0 || - ns_makecanon(zpk2->zpk_name, tb, sizeof tb) < 0) - return (-1); - return (strcasecmp(ta, tb)); -} - -static struct zpubkey * -tree_srch_pubkey (const char *name) { - struct zpubkey tkey, *key; - - DE_CONST(name, tkey.zpk_name); - if (trusted_keys == NULL) { - tree_init(&trusted_keys); - return (NULL); - } - key = (struct zpubkey *)tree_srch(&trusted_keys, compare_pubkey, - &tkey); - return (key); -} - -static DST_KEY * -find_public_key (const char *name, u_int16_t key_id) { - struct namebuf *knp; - struct hashbuf *htp; - struct databuf *dp; - const char *fname; - DST_KEY *key; - - ns_debug(ns_log_default, 5, "find_public_key(%s, %d)", name, key_id); - - htp = hashtab; - knp = nlookup (name, &htp, &fname, 0); - if (fname != name) - /* The name doesn't exist, so there's no key */ - return (NULL); - - for (dp = knp->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_type != ns_t_key || dp->d_secure < DB_S_SECURE) - continue; - key = dst_dnskey_to_key(name, dp->d_data, dp->d_size); - /* XXX what about multiple keys with same footprint? */ - if (key) { - if (key->dk_id == ntohs(key_id)) - return (key); - else - dst_free_key(key); - } - } - return (NULL); -} - - -static DST_KEY * -find_trusted_key (const char *name, u_int16_t key_id) { - struct zpubkey *zpk; - zpubkey_list keylist = tree_srch_pubkey (name); - - ns_debug(ns_log_default, 5, "find_trusted_key(%s, %d)", name, key_id); - - for (zpk = keylist; zpk; zpk = zpk->zpk_next) - if (zpk->zpk_key->dk_id == ntohs(key_id)) - return (zpk->zpk_key); - - return (NULL); -} - -int -add_trusted_key (const char *name, const int flags, const int proto, - const int alg, const char *str) -{ - zpubkey_list keylist; - struct zpubkey *zpk; - u_char buf[1024]; - int n; - - keylist = tree_srch_pubkey (name); - - zpk = (struct zpubkey *) memget (sizeof (struct zpubkey)); - if (zpk == NULL) - ns_panic(ns_log_default, 1, - "add_trusted_key: memget failed(%s)", name); - n = b64_pton(str, buf, sizeof(buf)); - if (n < 0) - goto failure; - zpk->zpk_key = dst_buffer_to_key(name, alg, flags, proto, buf, n); - if (zpk->zpk_key == NULL) { - ns_warning(ns_log_default, - "add_trusted_key: dst_buffer_to_key(%s) failed", - name); - goto failure; - } - zpk->zpk_name = zpk->zpk_key->dk_key_name; - zpk->zpk_next = NULL; - - if (keylist == NULL) { - if (tree_add (&trusted_keys, compare_pubkey, zpk, NULL) == NULL) - goto failure; - } - else { - struct zpubkey *tkey = keylist; - while (tkey->zpk_next) - tkey = tkey->zpk_next; - tkey->zpk_next = zpk; - } - - return (1); - failure: - memput(zpk, sizeof (struct zpubkey)); - return (0); -} - -/* Can the signer sign records for this name? This is a heuristic. */ -static int -can_sign(const char *name, const char *signer) { - return (ns_samedomain(name, signer) && - dn_count_labels(name) - dn_count_labels(signer) <= 2); -} - -static int -rrset_set_security(struct db_rrset *rrset, int slev) { - struct dnode *dnp; - - for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) - dnp->dp->d_secure = slev; - for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) - dnp->dp->d_secure = slev; - return (slev); -} - -static int -convert_databuf(struct databuf *dp, struct converted_databuf *cdp) { - u_char *bp = cdp->cd_data; - u_char *cp = dp->d_data; - u_char *eob = cdp->cd_data + cdp->cd_alloc; - int len; - u_char buf[MAXDNAME]; - - switch (dp->d_type) { - case ns_t_soa: - case ns_t_minfo: - case ns_t_rp: - if (eob - bp < (int)strlen((char *)cp) + 1) - return (-1); - if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) - return (-1); - len = ns_name_ntol(buf, bp, eob - bp); - if (len < 0) - return (-1); - bp += len; - cp += strlen((char *)cp) + 1; - - if (eob - bp < (int)strlen((char *)cp) + 1) - return (-1); - if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) - return (-1); - len = ns_name_ntol(buf, bp, eob - bp); - if (len < 0) - return (-1); - bp += len; - cp += strlen((char *)cp) + 1; - - if (dp->d_type == ns_t_soa) { - if (eob - bp < 5 * INT32SZ) - return (-1); - memcpy(bp, cp, 5 * INT32SZ); - bp += (5 * INT32SZ); - cp += (5 * INT32SZ); - } - - break; - - case ns_t_ns: - case ns_t_cname: - case ns_t_mb: - case ns_t_mg: - case ns_t_mr: - case ns_t_ptr: - case ns_t_nxt: - if (eob - bp < (int)strlen((char *)cp) + 1) - return (-1); - if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) - return (-1); - len = ns_name_ntol(buf, bp, eob - bp); - if (len < 0) - return (-1); - bp += len; - cp += (len = strlen((char *)cp) + 1); - - if (dp->d_type == ns_t_nxt) { - if (eob - bp < dp->d_size - len) - return (-1); - memcpy(bp, cp, dp->d_size - len); - bp += (dp->d_size - len); - cp += (dp->d_size - len); - } - break; - - case ns_t_srv: - if (eob - bp < 2 * INT16SZ) - return (-1); - memcpy(bp, cp, 2 * INT16SZ); - bp += (2 * INT16SZ); - cp += (2 * INT16SZ); - /* no break */ - case ns_t_rt: - case ns_t_mx: - case ns_t_afsdb: - case ns_t_px: - if (eob - bp < INT16SZ) - return (-1); - memcpy (bp, cp, INT16SZ); - bp += INT16SZ; - cp += INT16SZ; - - if (eob - bp < (int)strlen((char *)cp) + 1) - return (-1); - if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) - return (-1); - len = ns_name_ntol(buf, bp, eob - bp); - if (len < 0) - return (-1); - bp += len; - cp += strlen((char *)cp) + 1; - - if (dp->d_type == ns_t_px) { - if (eob - bp < (int)strlen((char *)cp) + 1) - return (-1); - if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) - return (-1); - len = ns_name_ntol(buf, bp, eob - bp); - if (len < 0) - return (-1); - bp += len; - cp += strlen((char *)cp) + 1; - } - break; - - default: - if (eob - bp < dp->d_size) - return (-1); - memcpy(bp, cp, dp->d_size); - bp += dp->d_size; - } - cdp->cd_size = bp - cdp->cd_data; - return (cdp->cd_size); -} - -static int -digest_rr(char *envelope, int elen, struct converted_databuf *cdp, - char *buffer, int blen) -{ - char *bp = buffer, *eob = buffer + blen; - - if (eob - bp < elen) - return (-1); - memcpy (bp, envelope, elen); - bp += elen; - - if (eob - bp < INT16SZ) - return (-1); - PUTSHORT(cdp->cd_size, bp); - - if (eob - bp < cdp->cd_size) - return (-1); - memcpy (bp, cdp->cd_data, cdp->cd_size); - bp += cdp->cd_size; - - return (bp - buffer); -} - -/* Sorts the converted databuf in the list */ -static void -insert_converted_databuf(struct converted_databuf *cdp, - struct converted_databuf **clist) -{ - struct converted_databuf *tcdp, *next; - int t; - -#define compare_cdatabuf(c1, c2, t) \ - (t = memcmp(c1->cd_data, c2->cd_data, MIN(c1->cd_size, c2->cd_size)), \ - t == 0 ? c1->cd_size - c2->cd_size : t) - - if (*clist == NULL) { - *clist = cdp; - return; - } - - tcdp = *clist; - if (compare_cdatabuf(cdp, tcdp, t) < 0) { - cdp->cd_next = tcdp; - *clist = cdp; - return; - } - - next = tcdp->cd_next; - while (next) { - if (compare_cdatabuf(cdp, next, t) < 0) { - cdp->cd_next = next; - tcdp->cd_next = cdp; - return; - } - tcdp = next; - next = next->cd_next; - } - tcdp->cd_next = cdp; -#undef compare_cdatabuf -} - -static void -free_clist(struct converted_databuf *clist) { - struct converted_databuf *cdp; - - while (clist != NULL) { - cdp = clist; - clist = clist->cd_next; - memput(cdp->cd_data, cdp->cd_alloc); - memput(cdp, sizeof(struct converted_databuf)); - } -} - -/* Removes all empty nodes from an rrset's SIG list. */ -static void -rrset_trim_sigs(struct db_rrset *rrset) { - struct dnode *dnp, *odnp, *ndnp; - - odnp = NULL; - dnp = rrset->rr_sigs; - while (dnp != NULL) { - if (dnp->dp != NULL) { - odnp = dnp; - dnp = dnp->dn_next; - } - else { - if (odnp != NULL) - odnp->dn_next = dnp->dn_next; - else - rrset->rr_sigs = dnp->dn_next; - ndnp = dnp->dn_next; - memput(dnp, sizeof(struct dnode)); - dnp = ndnp; - } - } -} - -static int -verify_set(struct db_rrset *rrset) { - DST_KEY *key = NULL; - struct sig_record *sigdata; - struct dnode *sigdn; - struct databuf *sigdp; - u_int32_t now; - u_int32_t exptime; - u_int32_t signtime; - char *signer; - u_char name_n[MAXDNAME]; - u_char *sig, *eom; - int trustedkey = 0, siglen, labels, len = 0, ret; - u_char *buffer = NULL, *bp; - u_char envelope[MAXDNAME+32], *ep; - struct dnode *dnp; - int bufsize = 2048; /* Large enough for MAXDNAME + SIG_HDR_SIZE */ - struct converted_databuf *clist = NULL, *cdp; - int dnssec_failed = 0, dnssec_succeeded = 0; - int return_value; - int i; - int expired = 0; - - if (rrset == NULL || rrset->rr_name == NULL) { - ns_warning (ns_log_default, "verify_set: missing rrset/name"); - return (rrset_set_security(rrset, DB_S_FAILED)); - } - - if (rrset->rr_sigs == NULL) - return (rrset_set_security(rrset, DB_S_INSECURE)); - - ns_debug(ns_log_default, 5, "verify_set(%s, %s, %s)", rrset->rr_name, - p_type(rrset->rr_type), p_class(rrset->rr_class)); - - now = time(NULL); - - for (sigdn = rrset->rr_sigs; sigdn != NULL; sigdn = sigdn->dn_next) { - u_int32_t namefield; - struct sig_record sigrec; - - sigdp = sigdn->dp; - - eom = sigdp->d_data + sigdp->d_size; - if (sigdp->d_size < SIG_HDR_SIZE) { - return_value = DB_S_FAILED; - goto end; - } - memcpy(&sigrec, sigdp->d_data, SIG_HDR_SIZE); - sigdata = &sigrec; - signer = (char *)sigdp->d_data + SIG_HDR_SIZE; - sig = (u_char *)signer + strlen(signer) + 1; - siglen = eom - sig; - - /* - * Don't verify a set if the SIG inception time is in - * the future. This should be fixed before 2038 (BEW) - */ - signtime = ntohl(sigdata->sig_time_n); - if (SEQ_GT(signtime, now)) - continue; - - /* An expired set is dropped, but the data is not. */ - exptime = ntohl(sigdata->sig_exp_n); - if (SEQ_GT(now, exptime)) { - expired++; - db_detach(&sigdn->dp); - sigdp = NULL; - continue; - } - - /* Cleanup from the last iteration if we continue'd */ - if (trustedkey == 0 && key != NULL) - dst_free_key(key); - - key = find_trusted_key(signer, sigdata->sig_keyid_n); - - if (key == NULL) { - trustedkey = 0; - key = find_public_key(signer, sigdata->sig_keyid_n); - } - else - trustedkey = 1; - - /* if we don't have the key, either - * - the data should be considered insecure - * - the sig is not a dnssec signature - */ - if (key == NULL) - continue; - - /* Can a key with this name sign the data? */ - if (!can_sign(rrset->rr_name, signer)) - continue; - - /* Check the protocol and flags of the key */ - if (key->dk_proto != NS_KEY_PROT_DNSSEC && - key->dk_proto != NS_KEY_PROT_ANY) - continue; - if (key->dk_flags & NS_KEY_NO_AUTH) - continue; - namefield = key->dk_flags & NS_KEY_NAME_TYPE; - if (namefield == NS_KEY_NAME_USER || - namefield == NS_KEY_NAME_RESERVED) - continue; - if (namefield == NS_KEY_NAME_ENTITY && - (key->dk_flags & NS_KEY_SIGNATORYMASK) == 0) - continue; - - /* - * If we're still here, we have a non-null key that's either - * a zone key or an entity key with signing authority. - */ - - if (buffer == NULL) { - bp = buffer = memget(bufsize); - if (bp == NULL) { - return_value = DB_S_FAILED; - goto end; - } - } - else - bp = buffer; - - - /* Digest the fixed portion of the SIG record */ - memcpy(bp, (char *) sigdata, SIG_HDR_SIZE); - bp += SIG_HDR_SIZE; - - /* Digest the signer's name, canonicalized */ - if (ns_name_pton(signer, name_n, sizeof name_n) < 0) { - return_value = DB_S_FAILED; - goto end; - } - i = ns_name_ntol(name_n, (u_char *)bp, bufsize - SIG_HDR_SIZE); - if (i < 0) { - return_value = DB_S_FAILED; - goto end; - } - bp += i; - - /* create the dns record envelope: - * <name><type><class><Original TTL> - */ - if (ns_name_pton(rrset->rr_name, name_n, sizeof name_n) < 0 || - ns_name_ntol(name_n, (u_char *)envelope, sizeof envelope) < 0) { - return_value = DB_S_FAILED; - goto end; - } - - labels = dn_count_labels(rrset->rr_name); - if (labels > sigdata->sig_labels_n) { - ep = envelope; - for (i=0; i < (labels - 1 - sigdata->sig_labels_n); i++) - ep += (*ep+1); - i = dn_skipname(ep, envelope + sizeof envelope); - if (i < 0) { - return_value = DB_S_FAILED; - goto end; - } - envelope[0] = '\001'; - envelope[1] = '*'; - memmove(envelope + 2, ep, i); - } - i = dn_skipname(envelope, envelope + sizeof envelope); - if (i < 0) { - return_value = DB_S_FAILED; - goto end; - } - ep = envelope + i; - PUTSHORT (rrset->rr_type, ep); - PUTSHORT (rrset->rr_class, ep); - if (envelope + sizeof(envelope) - ep < INT32SZ) { - return_value = DB_S_FAILED; - goto end; - } - memcpy (ep, &sigdata->sig_ottl_n, INT32SZ); - ep += INT32SZ; - - if (clist == NULL) { - for (dnp = rrset->rr_list; - dnp != NULL; - dnp = dnp->dn_next) - { - struct databuf *dp = dnp->dp; - - cdp = memget(sizeof(struct converted_databuf)); - if (cdp == NULL) { - return_value = DB_S_FAILED; - goto end; - } - memset(cdp, 0, sizeof(*cdp)); - /* Should be large enough... */ - cdp->cd_alloc = dp->d_size + 8; - cdp->cd_data = memget(cdp->cd_alloc); - if (cdp->cd_data == NULL) { - memput(cdp, sizeof(*cdp)); - return_value = DB_S_FAILED; - goto end; - } - while (convert_databuf(dp, cdp) < 0) { - memput(cdp->cd_data, cdp->cd_alloc); - cdp->cd_alloc *= 2; - cdp->cd_data = memget(cdp->cd_alloc); - if (cdp->cd_data == NULL) { - memput(cdp, sizeof(*cdp)); - return_value = DB_S_FAILED; - goto end; - } - } - insert_converted_databuf(cdp, &clist); - } - } - - for (cdp = clist; cdp != NULL; cdp = cdp->cd_next) { - len = digest_rr((char *)envelope, ep-envelope, cdp, - (char *)bp, bufsize - (bp - buffer)); - while (len < 0) { - u_char *newbuf; - - /* Double the buffer size */ - newbuf = memget(bufsize*2); - if (newbuf == NULL) { - return_value = DB_S_FAILED; - goto end; - } - memcpy(newbuf, buffer, bp - buffer); - bp = (bp - buffer) + newbuf; - memput(buffer, bufsize); - buffer = newbuf; - bufsize *= 2; - - len = digest_rr((char *)envelope, ep-envelope, - cdp, (char *)bp, - bufsize - (bp - buffer)); - } - bp += len; - } - - if (len < 0) { - return_value = DB_S_FAILED; - goto end; - } - - ret = dst_verify_data(SIG_MODE_ALL, key, NULL, buffer, - bp - buffer, sig, siglen); - - if (ret < 0) { - dnssec_failed++; - db_detach(&sigdn->dp); - sigdp = NULL; - } - else - dnssec_succeeded++; - } - -end: - if (dnssec_failed > 0 || expired > 0) - rrset_trim_sigs(rrset); - if (trustedkey == 0 && key != NULL) - dst_free_key(key); - - if (dnssec_failed > 0 && dnssec_succeeded == 0) { - ns_warning (ns_log_default, - "verify_set(%s, %s, %s) failed", - rrset->rr_name, p_type(rrset->rr_type), - p_class(rrset->rr_class)); - return_value = DB_S_FAILED; - } - else if (dnssec_succeeded > 0) - return_value = DB_S_SECURE; - else - return_value = DB_S_INSECURE; - free_clist(clist); - if (buffer != NULL) - memput(buffer, bufsize); - return (rrset_set_security(rrset, return_value)); -} - -static void -rrset_free(struct db_rrset *rrset) { - struct dnode *dnp; - - ns_debug(ns_log_default, 5, "rrset_free(%s)", rrset->rr_name); - - while (rrset->rr_list) { - dnp = rrset->rr_list; - rrset->rr_list = rrset->rr_list->dn_next; - if (dnp->dp != NULL) - db_detach(&dnp->dp); - memput(dnp, sizeof(struct dnode)); - } - while (rrset->rr_sigs) { - dnp = rrset->rr_sigs; - rrset->rr_sigs = rrset->rr_sigs->dn_next; - if (dnp->dp != NULL) - db_detach(&dnp->dp); - memput(dnp, sizeof(struct dnode)); - } -} - -/* - * This is called when we have an rrset with SIGs and no other data. - * Returns 1 if we either found the necessary data or if the SIG can be added - * with no other data. 0 indicates that the SIG cannot be added. - */ -static int -attach_data(struct db_rrset *rrset) { - int type, class; - struct databuf *dp, *newdp, *sigdp; - struct dnode *dnp; - struct namebuf *np; - struct hashbuf *htp; - char *signer; - const char *fname; - char *name = rrset->rr_name; - - sigdp = rrset->rr_sigs->dp; - - type = SIG_COVERS(sigdp); - class = sigdp->d_class; - signer = (char *)(sigdp + SIG_HDR_SIZE); - - /* First, see if the signer can sign data for the name. If not, - * it's not a DNSSEC signature, so we can insert it with no - * corresponding data. - */ - if (!can_sign(name, signer)) - return (1); - - htp = hashtab; - np = nlookup (name, &htp, &fname, 0); - if (fname != name) - return (0); - - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_type == type && dp->d_class == class) { - newdp = savedata(class, type, dp->d_ttl, dp->d_data, - dp->d_size); - dnp = (struct dnode *) memget (sizeof (struct dnode)); - if (dnp == NULL) - ns_panic(ns_log_default, 1, - "attach_data: memget failed"); - dnp->dp = newdp; - dnp->dn_next = rrset->rr_list; - rrset->rr_list = dnp; - } - } - if (rrset->rr_list != NULL) - return (1); - else - return (0); -} - -static int -rrset_db_update(struct db_rrset *rrset, int flags, struct hashbuf **htpp, - struct sockaddr_in from, int *rrcount) -{ - struct dnode *dnp; - int ret; - - /* If we have any unattached SIG records that are DNSSEC signatures, - * don't cache them unless we already have the corresponding data. - * If we do cache unattached SIGs, we run into problems later if we - * have a SIG X and get a query for type X. - */ - if (rrset->rr_list == NULL) { - if (attach_data(rrset) == 0) { - rrset_free(rrset); - return (OK); - } - - if (rrset->rr_list != NULL && - verify_set(rrset) == DB_S_FAILED) - { - rrset_free(rrset); - return (OK); - } - } - - for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) { - ret = db_update(rrset->rr_name, dnp->dp, dnp->dp, NULL, - flags, (*htpp), from); - if (ret != OK) { - /* XXX Probably should do rollback. */ - db_err(ret, rrset->rr_name, dnp->dp->d_type, - dnp->file, dnp->line); - if (ret != DATAEXISTS) { - rrset_free(rrset); - return (ret); - } - } - if (rrcount != NULL) - (*rrcount)++; - } - for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) { - if (dnp->dp == NULL) /* verifyset() can remove sigs */ - continue; - ret = db_update(rrset->rr_name, dnp->dp, dnp->dp, NULL, - flags, (*htpp), from); - if (ret != OK) { - /* XXX Probably should do rollback. */ - db_err(ret, rrset->rr_name, dnp->dp->d_type, - dnp->file, dnp->line); - if (ret != DATAEXISTS) { - rrset_free(rrset); - return (ret); - } - } - if (rrcount != NULL) - (*rrcount)++; - } - rrset_free(rrset); - return (OK); -} - -static int -rr_in_set(struct databuf *rr, struct dnode *set) { - struct dnode *dnp; - - if (set == NULL) - return (0); - - for(dnp = set; dnp != NULL; dnp = dnp->dn_next) { - if (dnp->dp->d_size == rr->d_size && - memcmp(dnp->dp->d_data, rr->d_data, dnp->dp->d_size) == 0) - return (1); - } - return (0); -} - -static int -add_to_rrset_list(struct db_rrset **rrsets, char *name, struct databuf *dp, - int line, const char *file) -{ - struct db_rrset *rrset = *rrsets; - struct dnode *dnp; - - while (rrset != NULL) { - if (rrset->rr_type != ns_t_nxt || dp->d_type != ns_t_nxt) { - if (dp->d_type == ns_t_sig) { - if ((int)SIG_COVERS(dp) == rrset->rr_type) - break; - } else { - if (dp->d_type == rrset->rr_type) - break; - } - } - else if (nxt_match_rrset(dp, rrset)) - break; - rrset = rrset->rr_next; - } - - if (rrset != NULL) { - if ((dp->d_type == ns_t_sig && rr_in_set(dp, rrset->rr_sigs)) || - (dp->d_type != ns_t_sig && rr_in_set(dp, rrset->rr_list))) - return (DATAEXISTS); - } else { - rrset = (struct db_rrset *) memget(sizeof(struct db_rrset)); - if (rrset == NULL) - ns_panic(ns_log_default, 1, - "add_to_rrset_list: memget failed(%s)", name); - memset(rrset, 0, sizeof(struct db_rrset)); - rrset->rr_name = savestr(name, 1); - rrset->rr_class = dp->d_class; - if (dp->d_type == ns_t_sig) - rrset->rr_type = SIG_COVERS(dp); - else - rrset->rr_type = dp->d_type; - rrset->rr_next = *rrsets; - *rrsets = rrset; - } - - dnp = (struct dnode *) memget(sizeof(struct dnode)); - if (dnp == NULL) - ns_panic(ns_log_default, 1, - "add_to_rrset_list: memget failed(%s)", name); - memset(dnp, 0, sizeof(struct dnode)); - dnp->dp = dp; - DRCNTINC(dnp->dp); - if (dp->d_type == ns_t_sig) { - if (rrset->rr_sigs != NULL) { - struct dnode *fdnp; - - /* Preserve the order of the RRs */ - /* Add this one to the end of the list */ - for (fdnp = rrset->rr_sigs; - fdnp->dn_next != NULL; - fdnp = fdnp->dn_next) - /* NULL */ ; - fdnp->dn_next = dnp; - } else - rrset->rr_sigs = dnp; - } else { - if (rrset->rr_list != NULL) { - struct dnode *fdnp; - - /* Preserve the order of the RRs */ - /* Add this one to the end of the list */ - for (fdnp = rrset->rr_list; - fdnp->dn_next != NULL; - fdnp = fdnp->dn_next) - /* NULL */ ; - fdnp->dn_next = dnp; - } else - rrset->rr_list = dnp; - } - dnp->file = file; - dnp->line = line; - return (0); -} - -static int -update_rrset_list(struct db_rrset **rrsets, int flags, struct hashbuf **htpp, - struct sockaddr_in from, int *rrcount) -{ - struct db_rrset *rrset = *rrsets, *next = NULL, *last = NULL; - int result = 0, tresult, cnameandother = 0; - - while (rrset != NULL) { - if (rrset->rr_type == ns_t_key) - break; - last = rrset; - rrset = rrset->rr_next; - } - - if (rrset != NULL && last != NULL) { - last->rr_next = rrset->rr_next; - rrset->rr_next = *rrsets; - *rrsets = rrset; - } - - rrset = *rrsets; - - while (rrset != NULL) { - if (verify_set(rrset) > DB_S_FAILED) { - ns_debug(ns_log_default, 10, - "update_rrset_list(%s, %s): set verified", - rrset->rr_name, p_type(rrset->rr_type)); - tresult = rrset_db_update(rrset, flags, htpp, - from, rrcount); - if (tresult == CNAMEANDOTHER) - cnameandother++; - if (tresult != OK) - result = tresult; - } - else { - rrset_free(rrset); - result = DNSSECFAIL; - } - rrset->rr_name = freestr(rrset->rr_name); - next = rrset->rr_next; - memput(rrset, sizeof(struct db_rrset)); - rrset = next; - } - *rrsets = NULL; - if (cnameandother != 0) - return (CNAMEANDOTHER); - return (result); -} - -int -db_set_update(char *name, struct databuf *dp, void **state, - int flags, struct hashbuf **htpp, struct sockaddr_in from, - int *rrcount, int line, const char *file) -{ - struct db_rrset **rrsets; - struct db_rrset *rrset; - int result = 0; - - ns_debug(ns_log_default, 5, "db_set_update(%s)", - (name == NULL) ? "<NULL>" : (*name == 0) ? "." : name); - - if (state == NULL) - ns_panic(ns_log_default, 1, - "Called db_set_update with state == NULL"); - - rrsets = (struct db_rrset **) state; - - if (*rrsets != NULL) { - rrset = *rrsets; - if (rrset->rr_name != NULL && dp != NULL && - name != NULL && ns_samename(name, rrset->rr_name) == 1 && - dp->d_class == rrset->rr_class) - return (add_to_rrset_list(rrsets, name, dp, - line, file)); - } - - if (*rrsets != NULL) - result = update_rrset_list(rrsets, flags, htpp, from, rrcount); - - if (dp != NULL) { - ns_debug(ns_log_default, 10, - "db_set_update(%s), creating new list", name); - - (void) add_to_rrset_list(rrsets, name, dp, line, file); - } - return (result); -} - -static int -nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset) { - if (rrset->rr_list != NULL) - return (nxtmatch(rrset->rr_name, dp, rrset->rr_list->dp)); - else - return (nxtmatch(rrset->rr_name, dp, rrset->rr_sigs->dp)); -} |