1238106Sdes/*
2238106Sdes * validator/val_anchor.c - validator trust anchor storage.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33238106Sdes * POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains storage for the trust anchors for the validator.
40238106Sdes */
41238106Sdes#include "config.h"
42238106Sdes#include <ctype.h>
43238106Sdes#include <ldns/dname.h>
44238106Sdes#include <ldns/host2wire.h>
45238106Sdes#include "validator/val_anchor.h"
46238106Sdes#include "validator/val_sigcrypt.h"
47238106Sdes#include "validator/autotrust.h"
48238106Sdes#include "util/data/packed_rrset.h"
49238106Sdes#include "util/data/dname.h"
50238106Sdes#include "util/log.h"
51238106Sdes#include "util/net_help.h"
52238106Sdes#include "util/config_file.h"
53238106Sdes#ifdef HAVE_GLOB_H
54238106Sdes#include <glob.h>
55238106Sdes#endif
56238106Sdes
57238106Sdesint
58238106Sdesanchor_cmp(const void* k1, const void* k2)
59238106Sdes{
60238106Sdes	int m;
61238106Sdes	struct trust_anchor* n1 = (struct trust_anchor*)k1;
62238106Sdes	struct trust_anchor* n2 = (struct trust_anchor*)k2;
63238106Sdes	/* no need to ntohs(class) because sort order is irrelevant */
64238106Sdes	if(n1->dclass != n2->dclass) {
65238106Sdes		if(n1->dclass < n2->dclass)
66238106Sdes			return -1;
67238106Sdes		return 1;
68238106Sdes	}
69238106Sdes	return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
70238106Sdes		&m);
71238106Sdes}
72238106Sdes
73238106Sdesstruct val_anchors*
74238106Sdesanchors_create(void)
75238106Sdes{
76238106Sdes	struct val_anchors* a = (struct val_anchors*)calloc(1, sizeof(*a));
77238106Sdes	if(!a)
78238106Sdes		return NULL;
79238106Sdes	a->tree = rbtree_create(anchor_cmp);
80238106Sdes	if(!a->tree) {
81238106Sdes		anchors_delete(a);
82238106Sdes		return NULL;
83238106Sdes	}
84238106Sdes	a->autr = autr_global_create();
85238106Sdes	if(!a->autr) {
86238106Sdes		anchors_delete(a);
87238106Sdes		return NULL;
88238106Sdes	}
89238106Sdes	lock_basic_init(&a->lock);
90238106Sdes	lock_protect(&a->lock, a, sizeof(*a));
91238106Sdes	lock_protect(&a->lock, a->autr, sizeof(*a->autr));
92238106Sdes	return a;
93238106Sdes}
94238106Sdes
95238106Sdes/** delete assembled rrset */
96238106Sdesstatic void
97238106Sdesassembled_rrset_delete(struct ub_packed_rrset_key* pkey)
98238106Sdes{
99238106Sdes	if(!pkey) return;
100238106Sdes	if(pkey->entry.data) {
101238106Sdes		struct packed_rrset_data* pd = (struct packed_rrset_data*)
102238106Sdes			pkey->entry.data;
103238106Sdes		free(pd->rr_data);
104238106Sdes		free(pd->rr_ttl);
105238106Sdes		free(pd->rr_len);
106238106Sdes		free(pd);
107238106Sdes	}
108238106Sdes	free(pkey->rk.dname);
109238106Sdes	free(pkey);
110238106Sdes}
111238106Sdes
112238106Sdes/** destroy locks in tree and delete autotrust anchors */
113238106Sdesstatic void
114238106Sdesanchors_delfunc(rbnode_t* elem, void* ATTR_UNUSED(arg))
115238106Sdes{
116238106Sdes	struct trust_anchor* ta = (struct trust_anchor*)elem;
117238106Sdes	if(!ta) return;
118238106Sdes	if(ta->autr) {
119238106Sdes		autr_point_delete(ta);
120238106Sdes	} else {
121238106Sdes		struct ta_key* p, *np;
122238106Sdes		lock_basic_destroy(&ta->lock);
123238106Sdes		free(ta->name);
124238106Sdes		p = ta->keylist;
125238106Sdes		while(p) {
126238106Sdes			np = p->next;
127238106Sdes			free(p->data);
128238106Sdes			free(p);
129238106Sdes			p = np;
130238106Sdes		}
131238106Sdes		assembled_rrset_delete(ta->ds_rrset);
132238106Sdes		assembled_rrset_delete(ta->dnskey_rrset);
133238106Sdes		free(ta);
134238106Sdes	}
135238106Sdes}
136238106Sdes
137238106Sdesvoid
138238106Sdesanchors_delete(struct val_anchors* anchors)
139238106Sdes{
140238106Sdes	if(!anchors)
141238106Sdes		return;
142238106Sdes	lock_unprotect(&anchors->lock, anchors->autr);
143238106Sdes	lock_unprotect(&anchors->lock, anchors);
144238106Sdes	lock_basic_destroy(&anchors->lock);
145238106Sdes	if(anchors->tree)
146238106Sdes		traverse_postorder(anchors->tree, anchors_delfunc, NULL);
147238106Sdes	free(anchors->tree);
148238106Sdes	autr_global_delete(anchors->autr);
149238106Sdes	free(anchors);
150238106Sdes}
151238106Sdes
152238106Sdesvoid
153238106Sdesanchors_init_parents_locked(struct val_anchors* anchors)
154238106Sdes{
155238106Sdes	struct trust_anchor* node, *prev = NULL, *p;
156238106Sdes	int m;
157238106Sdes	/* nobody else can grab locks because we hold the main lock.
158238106Sdes	 * Thus the previous items, after unlocked, are not deleted */
159238106Sdes	RBTREE_FOR(node, struct trust_anchor*, anchors->tree) {
160238106Sdes		lock_basic_lock(&node->lock);
161238106Sdes		node->parent = NULL;
162238106Sdes		if(!prev || prev->dclass != node->dclass) {
163238106Sdes			prev = node;
164238106Sdes			lock_basic_unlock(&node->lock);
165238106Sdes			continue;
166238106Sdes		}
167238106Sdes		(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
168238106Sdes			node->namelabs, &m); /* we know prev is smaller */
169238106Sdes		/* sort order like: . com. bla.com. zwb.com. net. */
170238106Sdes		/* find the previous, or parent-parent-parent */
171238106Sdes		for(p = prev; p; p = p->parent)
172238106Sdes			/* looking for name with few labels, a parent */
173238106Sdes			if(p->namelabs <= m) {
174238106Sdes				/* ==: since prev matched m, this is closest*/
175238106Sdes				/* <: prev matches more, but is not a parent,
176238106Sdes			 	* this one is a (grand)parent */
177238106Sdes				node->parent = p;
178238106Sdes				break;
179238106Sdes			}
180238106Sdes		lock_basic_unlock(&node->lock);
181238106Sdes		prev = node;
182238106Sdes	}
183238106Sdes}
184238106Sdes
185238106Sdes/** initialise parent pointers in the tree */
186238106Sdesstatic void
187238106Sdesinit_parents(struct val_anchors* anchors)
188238106Sdes{
189238106Sdes	lock_basic_lock(&anchors->lock);
190238106Sdes	anchors_init_parents_locked(anchors);
191238106Sdes	lock_basic_unlock(&anchors->lock);
192238106Sdes}
193238106Sdes
194238106Sdesstruct trust_anchor*
195238106Sdesanchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs,
196238106Sdes	size_t namelen, uint16_t dclass)
197238106Sdes{
198238106Sdes	struct trust_anchor key;
199238106Sdes	rbnode_t* n;
200238106Sdes	if(!name) return NULL;
201238106Sdes	key.node.key = &key;
202238106Sdes	key.name = name;
203238106Sdes	key.namelabs = namelabs;
204238106Sdes	key.namelen = namelen;
205238106Sdes	key.dclass = dclass;
206238106Sdes	lock_basic_lock(&anchors->lock);
207238106Sdes	n = rbtree_search(anchors->tree, &key);
208238106Sdes	if(n) {
209238106Sdes		lock_basic_lock(&((struct trust_anchor*)n->key)->lock);
210238106Sdes	}
211238106Sdes	lock_basic_unlock(&anchors->lock);
212238106Sdes	if(!n)
213238106Sdes		return NULL;
214238106Sdes	return (struct trust_anchor*)n->key;
215238106Sdes}
216238106Sdes
217238106Sdes/** create new trust anchor object */
218238106Sdesstatic struct trust_anchor*
219238106Sdesanchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs,
220238106Sdes	size_t namelen, uint16_t dclass, int lockit)
221238106Sdes{
222238106Sdes#ifdef UNBOUND_DEBUG
223238106Sdes	rbnode_t* r;
224238106Sdes#endif
225238106Sdes	struct trust_anchor* ta = (struct trust_anchor*)malloc(
226238106Sdes		sizeof(struct trust_anchor));
227238106Sdes	if(!ta)
228238106Sdes		return NULL;
229238106Sdes	memset(ta, 0, sizeof(*ta));
230238106Sdes	ta->node.key = ta;
231238106Sdes	ta->name = memdup(name, namelen);
232238106Sdes	if(!ta->name) {
233238106Sdes		free(ta);
234238106Sdes		return NULL;
235238106Sdes	}
236238106Sdes	ta->namelabs = namelabs;
237238106Sdes	ta->namelen = namelen;
238238106Sdes	ta->dclass = dclass;
239238106Sdes	lock_basic_init(&ta->lock);
240238106Sdes	if(lockit) {
241238106Sdes		lock_basic_lock(&anchors->lock);
242238106Sdes	}
243238106Sdes#ifdef UNBOUND_DEBUG
244238106Sdes	r =
245238106Sdes#endif
246238106Sdes	rbtree_insert(anchors->tree, &ta->node);
247238106Sdes	if(lockit) {
248238106Sdes		lock_basic_unlock(&anchors->lock);
249238106Sdes	}
250238106Sdes	log_assert(r != NULL);
251238106Sdes	return ta;
252238106Sdes}
253238106Sdes
254238106Sdes/** find trustanchor key by exact data match */
255238106Sdesstatic struct ta_key*
256238106Sdesanchor_find_key(struct trust_anchor* ta, uint8_t* rdata, size_t rdata_len,
257238106Sdes	uint16_t type)
258238106Sdes{
259238106Sdes	struct ta_key* k;
260238106Sdes	for(k = ta->keylist; k; k = k->next) {
261238106Sdes		if(k->type == type && k->len == rdata_len &&
262238106Sdes			memcmp(k->data, rdata, rdata_len) == 0)
263238106Sdes			return k;
264238106Sdes	}
265238106Sdes	return NULL;
266238106Sdes}
267238106Sdes
268238106Sdes/** create new trustanchor key */
269238106Sdesstatic struct ta_key*
270238106Sdesanchor_new_ta_key(uint8_t* rdata, size_t rdata_len, uint16_t type)
271238106Sdes{
272238106Sdes	struct ta_key* k = (struct ta_key*)malloc(sizeof(*k));
273238106Sdes	if(!k)
274238106Sdes		return NULL;
275238106Sdes	memset(k, 0, sizeof(*k));
276238106Sdes	k->data = memdup(rdata, rdata_len);
277238106Sdes	if(!k->data) {
278238106Sdes		free(k);
279238106Sdes		return NULL;
280238106Sdes	}
281238106Sdes	k->len = rdata_len;
282238106Sdes	k->type = type;
283238106Sdes	return k;
284238106Sdes}
285238106Sdes
286238106Sdes/**
287238106Sdes * This routine adds a new RR to a trust anchor. The trust anchor may not
288238106Sdes * exist yet, and is created if not. The RR can be DS or DNSKEY.
289238106Sdes * This routine will also remove duplicates; storing them only once.
290238106Sdes * @param anchors: anchor storage.
291238106Sdes * @param name: name of trust anchor (wireformat)
292238106Sdes * @param type: type or RR
293238106Sdes * @param dclass: class of RR
294238106Sdes * @param rdata: rdata wireformat, starting with rdlength.
295238106Sdes *	If NULL, nothing is stored, but an entry is created.
296238106Sdes * @param rdata_len: length of rdata including rdlength.
297238106Sdes * @return: NULL on error, else the trust anchor.
298238106Sdes */
299238106Sdesstatic struct trust_anchor*
300238106Sdesanchor_store_new_key(struct val_anchors* anchors, uint8_t* name, uint16_t type,
301238106Sdes	uint16_t dclass, uint8_t* rdata, size_t rdata_len)
302238106Sdes{
303238106Sdes	struct ta_key* k;
304238106Sdes	struct trust_anchor* ta;
305238106Sdes	int namelabs;
306238106Sdes	size_t namelen;
307238106Sdes	namelabs = dname_count_size_labels(name, &namelen);
308238106Sdes	if(type != LDNS_RR_TYPE_DS && type != LDNS_RR_TYPE_DNSKEY) {
309238106Sdes		log_err("Bad type for trust anchor");
310238106Sdes		return 0;
311238106Sdes	}
312238106Sdes	/* lookup or create trustanchor */
313238106Sdes	ta = anchor_find(anchors, name, namelabs, namelen, dclass);
314238106Sdes	if(!ta) {
315238106Sdes		ta = anchor_new_ta(anchors, name, namelabs, namelen, dclass, 1);
316238106Sdes		if(!ta)
317238106Sdes			return NULL;
318238106Sdes		lock_basic_lock(&ta->lock);
319238106Sdes	}
320238106Sdes	if(!rdata) {
321238106Sdes		lock_basic_unlock(&ta->lock);
322238106Sdes		return ta;
323238106Sdes	}
324238106Sdes	/* look for duplicates */
325238106Sdes	if(anchor_find_key(ta, rdata, rdata_len, type)) {
326238106Sdes		lock_basic_unlock(&ta->lock);
327238106Sdes		return ta;
328238106Sdes	}
329238106Sdes	k = anchor_new_ta_key(rdata, rdata_len, type);
330238106Sdes	if(!k) {
331238106Sdes		lock_basic_unlock(&ta->lock);
332238106Sdes		return NULL;
333238106Sdes	}
334238106Sdes	/* add new key */
335238106Sdes	if(type == LDNS_RR_TYPE_DS)
336238106Sdes		ta->numDS++;
337238106Sdes	else	ta->numDNSKEY++;
338238106Sdes	k->next = ta->keylist;
339238106Sdes	ta->keylist = k;
340238106Sdes	lock_basic_unlock(&ta->lock);
341238106Sdes	return ta;
342238106Sdes}
343238106Sdes
344238106Sdes/**
345238106Sdes * Add new RR. It converts ldns RR to wire format.
346238106Sdes * @param anchors: anchor storage.
347238106Sdes * @param buffer: parsing buffer.
348238106Sdes * @param rr: the rr (allocated by caller).
349238106Sdes * @return NULL on error, else the trust anchor.
350238106Sdes */
351238106Sdesstatic struct trust_anchor*
352238106Sdesanchor_store_new_rr(struct val_anchors* anchors, ldns_buffer* buffer,
353238106Sdes	ldns_rr* rr)
354238106Sdes{
355238106Sdes	struct trust_anchor* ta;
356238106Sdes	ldns_rdf* owner = ldns_rr_owner(rr);
357238106Sdes	ldns_status status;
358238106Sdes	ldns_buffer_clear(buffer);
359238106Sdes	ldns_buffer_skip(buffer, 2); /* skip rdatalen */
360238106Sdes	status = ldns_rr_rdata2buffer_wire(buffer, rr);
361238106Sdes	if(status != LDNS_STATUS_OK) {
362238106Sdes		log_err("error converting trustanchor to wireformat: %s",
363238106Sdes			ldns_get_errorstr_by_id(status));
364238106Sdes		return NULL;
365238106Sdes	}
366238106Sdes	ldns_buffer_flip(buffer);
367238106Sdes	ldns_buffer_write_u16_at(buffer, 0, ldns_buffer_limit(buffer) - 2);
368238106Sdes
369238106Sdes	if(!(ta=anchor_store_new_key(anchors, ldns_rdf_data(owner),
370238106Sdes		ldns_rr_get_type(rr), ldns_rr_get_class(rr),
371238106Sdes		ldns_buffer_begin(buffer), ldns_buffer_limit(buffer)))) {
372238106Sdes		return NULL;
373238106Sdes	}
374238106Sdes	log_nametypeclass(VERB_QUERY, "adding trusted key",
375238106Sdes		ldns_rdf_data(owner),
376238106Sdes		ldns_rr_get_type(rr), ldns_rr_get_class(rr));
377238106Sdes	return ta;
378238106Sdes}
379238106Sdes
380238106Sdes/**
381238106Sdes * Insert insecure anchor
382238106Sdes * @param anchors: anchor storage.
383238106Sdes * @param str: the domain name.
384238106Sdes * @return NULL on error, Else last trust anchor point
385238106Sdes */
386238106Sdesstatic struct trust_anchor*
387238106Sdesanchor_insert_insecure(struct val_anchors* anchors, const char* str)
388238106Sdes{
389238106Sdes	struct trust_anchor* ta;
390238106Sdes	ldns_rdf* nm = ldns_dname_new_frm_str(str);
391238106Sdes	if(!nm) {
392238106Sdes		log_err("parse error in domain name '%s'", str);
393238106Sdes		return NULL;
394238106Sdes	}
395238106Sdes	ta = anchor_store_new_key(anchors, ldns_rdf_data(nm), LDNS_RR_TYPE_DS,
396238106Sdes		LDNS_RR_CLASS_IN, NULL, 0);
397238106Sdes	ldns_rdf_deep_free(nm);
398238106Sdes	return ta;
399238106Sdes}
400238106Sdes
401238106Sdesstruct trust_anchor*
402238106Sdesanchor_store_str(struct val_anchors* anchors, ldns_buffer* buffer,
403238106Sdes	const char* str)
404238106Sdes{
405238106Sdes	struct trust_anchor* ta;
406238106Sdes	ldns_rr* rr = NULL;
407238106Sdes	ldns_status status = ldns_rr_new_frm_str(&rr, str, 0, NULL, NULL);
408238106Sdes	if(status != LDNS_STATUS_OK) {
409238106Sdes		log_err("error parsing trust anchor: %s",
410238106Sdes			ldns_get_errorstr_by_id(status));
411238106Sdes		ldns_rr_free(rr);
412238106Sdes		return NULL;
413238106Sdes	}
414238106Sdes	if(!(ta=anchor_store_new_rr(anchors, buffer, rr))) {
415238106Sdes		log_err("out of memory");
416238106Sdes		ldns_rr_free(rr);
417238106Sdes		return NULL;
418238106Sdes	}
419238106Sdes	ldns_rr_free(rr);
420238106Sdes	return ta;
421238106Sdes}
422238106Sdes
423238106Sdes/**
424238106Sdes * Read a file with trust anchors
425238106Sdes * @param anchors: anchor storage.
426238106Sdes * @param buffer: parsing buffer.
427238106Sdes * @param fname: string.
428238106Sdes * @param onlyone: only one trust anchor allowed in file.
429238106Sdes * @return NULL on error. Else last trust-anchor point.
430238106Sdes */
431238106Sdesstatic struct trust_anchor*
432238106Sdesanchor_read_file(struct val_anchors* anchors, ldns_buffer* buffer,
433238106Sdes	const char* fname, int onlyone)
434238106Sdes{
435238106Sdes	struct trust_anchor* ta = NULL, *tanew;
436238106Sdes	uint32_t default_ttl = 3600;
437238106Sdes	ldns_rdf* origin = NULL, *prev = NULL;
438238106Sdes	int line_nr = 1;
439238106Sdes	ldns_status status;
440238106Sdes	ldns_rr* rr;
441238106Sdes	int ok = 1;
442238106Sdes	FILE* in = fopen(fname, "r");
443238106Sdes	if(!in) {
444238106Sdes		log_err("error opening file %s: %s", fname, strerror(errno));
445238106Sdes		return 0;
446238106Sdes	}
447238106Sdes	while(!feof(in)) {
448238106Sdes		rr = NULL;
449238106Sdes		status = ldns_rr_new_frm_fp_l(&rr, in, &default_ttl, &origin,
450238106Sdes			&prev, &line_nr);
451238106Sdes		if(status == LDNS_STATUS_SYNTAX_EMPTY /* empty line */
452238106Sdes			|| status == LDNS_STATUS_SYNTAX_TTL /* $TTL */
453238106Sdes			|| status == LDNS_STATUS_SYNTAX_ORIGIN /* $ORIGIN */)
454238106Sdes			continue;
455238106Sdes		if(status != LDNS_STATUS_OK) {
456238106Sdes			log_err("parse error in %s:%d : %s", fname, line_nr,
457238106Sdes				ldns_get_errorstr_by_id(status));
458238106Sdes			ldns_rr_free(rr);
459238106Sdes			ok = 0;
460238106Sdes			break;
461238106Sdes		}
462238106Sdes		if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS &&
463238106Sdes			ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) {
464238106Sdes			ldns_rr_free(rr);
465238106Sdes			continue;
466238106Sdes		}
467238106Sdes		if(!(tanew=anchor_store_new_rr(anchors, buffer, rr))) {
468238106Sdes			log_err("error at %s line %d", fname, line_nr);
469238106Sdes			ldns_rr_free(rr);
470238106Sdes			ok = 0;
471238106Sdes			break;
472238106Sdes		}
473238106Sdes		if(onlyone && ta && ta != tanew) {
474238106Sdes			log_err("error at %s line %d: no multiple anchor "
475238106Sdes				"domains allowed (you can have multiple "
476238106Sdes				"keys, but they must have the same name).",
477238106Sdes				fname, line_nr);
478238106Sdes			ldns_rr_free(rr);
479238106Sdes			ok = 0;
480238106Sdes			break;
481238106Sdes		}
482238106Sdes		ta = tanew;
483238106Sdes		ldns_rr_free(rr);
484238106Sdes	}
485238106Sdes	ldns_rdf_deep_free(origin);
486238106Sdes	ldns_rdf_deep_free(prev);
487238106Sdes	fclose(in);
488238106Sdes	if(!ok) return NULL;
489238106Sdes	/* empty file is OK when multiple anchors are allowed */
490238106Sdes	if(!onlyone && !ta) return (struct trust_anchor*)1;
491238106Sdes	return ta;
492238106Sdes}
493238106Sdes
494238106Sdes/** skip file to end of line */
495238106Sdesstatic void
496238106Sdesskip_to_eol(FILE* in)
497238106Sdes{
498238106Sdes	int c;
499238106Sdes	while((c = getc(in)) != EOF ) {
500238106Sdes		if(c == '\n')
501238106Sdes			return;
502238106Sdes	}
503238106Sdes}
504238106Sdes
505238106Sdes/** true for special characters in bind configs */
506238106Sdesstatic int
507238106Sdesis_bind_special(int c)
508238106Sdes{
509238106Sdes	switch(c) {
510238106Sdes		case '{':
511238106Sdes		case '}':
512238106Sdes		case '"':
513238106Sdes		case ';':
514238106Sdes			return 1;
515238106Sdes	}
516238106Sdes	return 0;
517238106Sdes}
518238106Sdes
519238106Sdes/**
520238106Sdes * Read a keyword skipping bind comments; spaces, specials, restkeywords.
521238106Sdes * The file is split into the following tokens:
522238106Sdes *	* special characters, on their own, rdlen=1, { } doublequote ;
523238106Sdes *	* whitespace becomes a single ' ' or tab. Newlines become spaces.
524238106Sdes *	* other words ('keywords')
525238106Sdes *	* comments are skipped if desired
526238106Sdes *		/ / C++ style comment to end of line
527238106Sdes *		# to end of line
528238106Sdes *		/ * C style comment * /
529238106Sdes * @param in: file to read from.
530238106Sdes * @param buf: buffer, what is read is stored after current buffer position.
531238106Sdes *	Space is left in the buffer to write a terminating 0.
532238106Sdes * @param line: line number is increased per line, for error reports.
533238106Sdes * @param comments: if 0, comments are not possible and become text.
534238106Sdes *	if 1, comments are skipped entirely.
535238106Sdes *	In BIND files, this is when reading quoted strings, for example
536238106Sdes *	" base 64 text with / / in there "
537238106Sdes * @return the number of character written to the buffer.
538238106Sdes *	0 on end of file.
539238106Sdes */
540238106Sdesstatic int
541238106Sdesreadkeyword_bindfile(FILE* in, ldns_buffer* buf, int* line, int comments)
542238106Sdes{
543238106Sdes	int c;
544238106Sdes	int numdone = 0;
545238106Sdes	while((c = getc(in)) != EOF ) {
546238106Sdes		if(comments && c == '#') {	/*   # blabla   */
547238106Sdes			skip_to_eol(in);
548238106Sdes			(*line)++;
549238106Sdes			continue;
550238106Sdes		} else if(comments && c=='/' && numdone>0 && /* /_/ bla*/
551238106Sdes			ldns_buffer_read_u8_at(buf,
552238106Sdes			ldns_buffer_position(buf)-1) == '/') {
553238106Sdes			ldns_buffer_skip(buf, -1);
554238106Sdes			numdone--;
555238106Sdes			skip_to_eol(in);
556238106Sdes			(*line)++;
557238106Sdes			continue;
558238106Sdes		} else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */
559238106Sdes			ldns_buffer_read_u8_at(buf,
560238106Sdes			ldns_buffer_position(buf)-1) == '/') {
561238106Sdes			ldns_buffer_skip(buf, -1);
562238106Sdes			numdone--;
563238106Sdes			/* skip to end of comment */
564238106Sdes			while(c != EOF && (c=getc(in)) != EOF ) {
565238106Sdes				if(c == '*') {
566238106Sdes					if((c=getc(in)) == '/')
567238106Sdes						break;
568238106Sdes				}
569238106Sdes				if(c == '\n')
570238106Sdes					(*line)++;
571238106Sdes			}
572238106Sdes			continue;
573238106Sdes		}
574238106Sdes		/* not a comment, complete the keyword */
575238106Sdes		if(numdone > 0) {
576238106Sdes			/* check same type */
577238106Sdes			if(isspace(c)) {
578238106Sdes				ungetc(c, in);
579238106Sdes				return numdone;
580238106Sdes			}
581238106Sdes			if(is_bind_special(c)) {
582238106Sdes				ungetc(c, in);
583238106Sdes				return numdone;
584238106Sdes			}
585238106Sdes		}
586238106Sdes		if(c == '\n') {
587238106Sdes			c = ' ';
588238106Sdes			(*line)++;
589238106Sdes		}
590238106Sdes		/* space for 1 char + 0 string terminator */
591238106Sdes		if(ldns_buffer_remaining(buf) < 2) {
592238106Sdes			fatal_exit("trusted-keys, %d, string too long", *line);
593238106Sdes		}
594238106Sdes		ldns_buffer_write_u8(buf, (uint8_t)c);
595238106Sdes		numdone++;
596238106Sdes		if(isspace(c)) {
597238106Sdes			/* collate whitespace into ' ' */
598238106Sdes			while((c = getc(in)) != EOF ) {
599238106Sdes				if(c == '\n')
600238106Sdes					(*line)++;
601238106Sdes				if(!isspace(c)) {
602238106Sdes					ungetc(c, in);
603238106Sdes					break;
604238106Sdes				}
605238106Sdes			}
606238106Sdes			return numdone;
607238106Sdes		}
608238106Sdes		if(is_bind_special(c))
609238106Sdes			return numdone;
610238106Sdes	}
611238106Sdes	return numdone;
612238106Sdes}
613238106Sdes
614238106Sdes/** skip through file to { or ; */
615238106Sdesstatic int
616238106Sdesskip_to_special(FILE* in, ldns_buffer* buf, int* line, int spec)
617238106Sdes{
618238106Sdes	int rdlen;
619238106Sdes	ldns_buffer_clear(buf);
620238106Sdes	while((rdlen=readkeyword_bindfile(in, buf, line, 1))) {
621238106Sdes		if(rdlen == 1 && isspace((int)*ldns_buffer_begin(buf))) {
622238106Sdes			ldns_buffer_clear(buf);
623238106Sdes			continue;
624238106Sdes		}
625238106Sdes		if(rdlen != 1 || *ldns_buffer_begin(buf) != (uint8_t)spec) {
626238106Sdes			ldns_buffer_write_u8(buf, 0);
627238106Sdes			log_err("trusted-keys, line %d, expected %c",
628238106Sdes				*line, spec);
629238106Sdes			return 0;
630238106Sdes		}
631238106Sdes		return 1;
632238106Sdes	}
633238106Sdes	log_err("trusted-keys, line %d, expected %c got EOF", *line, spec);
634238106Sdes	return 0;
635238106Sdes}
636238106Sdes
637238106Sdes/**
638238106Sdes * read contents of trusted-keys{ ... ; clauses and insert keys into storage.
639238106Sdes * @param anchors: where to store keys
640238106Sdes * @param buf: buffer to use
641238106Sdes * @param line: line number in file
642238106Sdes * @param in: file to read from.
643238106Sdes * @return 0 on error.
644238106Sdes */
645238106Sdesstatic int
646238106Sdesprocess_bind_contents(struct val_anchors* anchors, ldns_buffer* buf,
647238106Sdes	int* line, FILE* in)
648238106Sdes{
649238106Sdes	/* loop over contents, collate strings before ; */
650238106Sdes	/* contents is (numbered): 0   1    2  3 4   5  6 7 8    */
651238106Sdes	/*                           name. 257 3 5 base64 base64 */
652238106Sdes	/* quoted value:           0 "111"  0  0 0   0  0 0 0    */
653238106Sdes	/* comments value:         1 "000"  1  1  1 "0  0 0 0"  1 */
654238106Sdes	int contnum = 0;
655238106Sdes	int quoted = 0;
656238106Sdes	int comments = 1;
657238106Sdes	int rdlen;
658238106Sdes	char* str = 0;
659238106Sdes	ldns_buffer_clear(buf);
660238106Sdes	while((rdlen=readkeyword_bindfile(in, buf, line, comments))) {
661238106Sdes		if(rdlen == 1 && ldns_buffer_position(buf) == 1
662238106Sdes			&& isspace((int)*ldns_buffer_begin(buf))) {
663238106Sdes			/* starting whitespace is removed */
664238106Sdes			ldns_buffer_clear(buf);
665238106Sdes			continue;
666238106Sdes		} else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == '"') {
667238106Sdes			/* remove " from the string */
668238106Sdes			if(contnum == 0) {
669238106Sdes				quoted = 1;
670238106Sdes				comments = 0;
671238106Sdes			}
672238106Sdes			ldns_buffer_skip(buf, -1);
673238106Sdes			if(contnum > 0 && quoted) {
674238106Sdes				if(ldns_buffer_remaining(buf) < 8+1) {
675238106Sdes					log_err("line %d, too long", *line);
676238106Sdes					return 0;
677238106Sdes				}
678238106Sdes				ldns_buffer_write(buf, " DNSKEY ", 8);
679238106Sdes				quoted = 0;
680238106Sdes				comments = 1;
681238106Sdes			} else if(contnum > 0)
682238106Sdes				comments = !comments;
683238106Sdes			continue;
684238106Sdes		} else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == ';') {
685238106Sdes
686238106Sdes			if(contnum < 5) {
687238106Sdes				ldns_buffer_write_u8(buf, 0);
688238106Sdes				log_err("line %d, bad key", *line);
689238106Sdes				return 0;
690238106Sdes			}
691238106Sdes			ldns_buffer_skip(buf, -1);
692238106Sdes			ldns_buffer_write_u8(buf, 0);
693238106Sdes			str = strdup((char*)ldns_buffer_begin(buf));
694238106Sdes			if(!str) {
695238106Sdes				log_err("line %d, allocation failure", *line);
696238106Sdes				return 0;
697238106Sdes			}
698238106Sdes			if(!anchor_store_str(anchors, buf, str)) {
699238106Sdes				log_err("line %d, bad key", *line);
700238106Sdes				free(str);
701238106Sdes				return 0;
702238106Sdes			}
703238106Sdes			free(str);
704238106Sdes			ldns_buffer_clear(buf);
705238106Sdes			contnum = 0;
706238106Sdes			quoted = 0;
707238106Sdes			comments = 1;
708238106Sdes			continue;
709238106Sdes		} else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == '}') {
710238106Sdes			if(contnum > 0) {
711238106Sdes				ldns_buffer_write_u8(buf, 0);
712238106Sdes				log_err("line %d, bad key before }", *line);
713238106Sdes				return 0;
714238106Sdes			}
715238106Sdes			return 1;
716238106Sdes		} else if(rdlen == 1 &&
717238106Sdes			isspace((int)ldns_buffer_current(buf)[-1])) {
718238106Sdes			/* leave whitespace here */
719238106Sdes		} else {
720238106Sdes			/* not space or whatnot, so actual content */
721238106Sdes			contnum ++;
722238106Sdes			if(contnum == 1 && !quoted) {
723238106Sdes				if(ldns_buffer_remaining(buf) < 8+1) {
724238106Sdes					log_err("line %d, too long", *line);
725238106Sdes					return 0;
726238106Sdes				}
727238106Sdes				ldns_buffer_write(buf, " DNSKEY ", 8);
728238106Sdes			}
729238106Sdes		}
730238106Sdes	}
731238106Sdes
732238106Sdes	log_err("line %d, EOF before }", *line);
733238106Sdes	return 0;
734238106Sdes}
735238106Sdes
736238106Sdes/**
737238106Sdes * Read a BIND9 like file with trust anchors in named.conf format.
738238106Sdes * @param anchors: anchor storage.
739238106Sdes * @param buffer: parsing buffer.
740238106Sdes * @param fname: string.
741238106Sdes * @return false on error.
742238106Sdes */
743238106Sdesstatic int
744238106Sdesanchor_read_bind_file(struct val_anchors* anchors, ldns_buffer* buffer,
745238106Sdes	const char* fname)
746238106Sdes{
747238106Sdes	int line_nr = 1;
748238106Sdes	FILE* in = fopen(fname, "r");
749238106Sdes	int rdlen = 0;
750238106Sdes	if(!in) {
751238106Sdes		log_err("error opening file %s: %s", fname, strerror(errno));
752238106Sdes		return 0;
753238106Sdes	}
754238106Sdes	verbose(VERB_QUERY, "reading in bind-compat-mode: '%s'", fname);
755238106Sdes	/* scan for  trusted-keys  keyword, ignore everything else */
756238106Sdes	ldns_buffer_clear(buffer);
757238106Sdes	while((rdlen=readkeyword_bindfile(in, buffer, &line_nr, 1)) != 0) {
758238106Sdes		if(rdlen != 12 || strncmp((char*)ldns_buffer_begin(buffer),
759238106Sdes			"trusted-keys", 12) != 0) {
760238106Sdes			ldns_buffer_clear(buffer);
761238106Sdes			/* ignore everything but trusted-keys */
762238106Sdes			continue;
763238106Sdes		}
764238106Sdes		if(!skip_to_special(in, buffer, &line_nr, '{')) {
765238106Sdes			log_err("error in trusted key: \"%s\"", fname);
766238106Sdes			fclose(in);
767238106Sdes			return 0;
768238106Sdes		}
769238106Sdes		/* process contents */
770238106Sdes		if(!process_bind_contents(anchors, buffer, &line_nr, in)) {
771238106Sdes			log_err("error in trusted key: \"%s\"", fname);
772238106Sdes			fclose(in);
773238106Sdes			return 0;
774238106Sdes		}
775238106Sdes		if(!skip_to_special(in, buffer, &line_nr, ';')) {
776238106Sdes			log_err("error in trusted key: \"%s\"", fname);
777238106Sdes			fclose(in);
778238106Sdes			return 0;
779238106Sdes		}
780238106Sdes		ldns_buffer_clear(buffer);
781238106Sdes	}
782238106Sdes	fclose(in);
783238106Sdes	return 1;
784238106Sdes}
785238106Sdes
786238106Sdes/**
787238106Sdes * Read a BIND9 like files with trust anchors in named.conf format.
788238106Sdes * Performs wildcard processing of name.
789238106Sdes * @param anchors: anchor storage.
790238106Sdes * @param buffer: parsing buffer.
791238106Sdes * @param pat: pattern string. (can be wildcarded)
792238106Sdes * @return false on error.
793238106Sdes */
794238106Sdesstatic int
795238106Sdesanchor_read_bind_file_wild(struct val_anchors* anchors, ldns_buffer* buffer,
796238106Sdes	const char* pat)
797238106Sdes{
798238106Sdes#ifdef HAVE_GLOB
799238106Sdes	glob_t g;
800238106Sdes	size_t i;
801238106Sdes	int r, flags;
802238106Sdes	if(!strchr(pat, '*') && !strchr(pat, '?') && !strchr(pat, '[') &&
803238106Sdes		!strchr(pat, '{') && !strchr(pat, '~')) {
804238106Sdes		return anchor_read_bind_file(anchors, buffer, pat);
805238106Sdes	}
806238106Sdes	verbose(VERB_QUERY, "wildcard found, processing %s", pat);
807238106Sdes	flags = 0
808238106Sdes#ifdef GLOB_ERR
809238106Sdes		| GLOB_ERR
810238106Sdes#endif
811238106Sdes#ifdef GLOB_NOSORT
812238106Sdes		| GLOB_NOSORT
813238106Sdes#endif
814238106Sdes#ifdef GLOB_BRACE
815238106Sdes		| GLOB_BRACE
816238106Sdes#endif
817238106Sdes#ifdef GLOB_TILDE
818238106Sdes		| GLOB_TILDE
819238106Sdes#endif
820238106Sdes	;
821238106Sdes	memset(&g, 0, sizeof(g));
822238106Sdes	r = glob(pat, flags, NULL, &g);
823238106Sdes	if(r) {
824238106Sdes		/* some error */
825238106Sdes		if(r == GLOB_NOMATCH) {
826238106Sdes			verbose(VERB_QUERY, "trusted-keys-file: "
827238106Sdes				"no matches for %s", pat);
828238106Sdes			return 1;
829238106Sdes		} else if(r == GLOB_NOSPACE) {
830238106Sdes			log_err("wildcard trusted-keys-file %s: "
831238106Sdes				"pattern out of memory", pat);
832238106Sdes		} else if(r == GLOB_ABORTED) {
833238106Sdes			log_err("wildcard trusted-keys-file %s: expansion "
834238106Sdes				"aborted (%s)", pat, strerror(errno));
835238106Sdes		} else {
836238106Sdes			log_err("wildcard trusted-keys-file %s: expansion "
837238106Sdes				"failed (%s)", pat, strerror(errno));
838238106Sdes		}
839249141Sdes		/* ignore globs that yield no files */
840249141Sdes		return 1;
841238106Sdes	}
842238106Sdes	/* process files found, if any */
843238106Sdes	for(i=0; i<(size_t)g.gl_pathc; i++) {
844238106Sdes		if(!anchor_read_bind_file(anchors, buffer, g.gl_pathv[i])) {
845238106Sdes			log_err("error reading wildcard "
846238106Sdes				"trusted-keys-file: %s", g.gl_pathv[i]);
847238106Sdes			globfree(&g);
848238106Sdes			return 0;
849238106Sdes		}
850238106Sdes	}
851238106Sdes	globfree(&g);
852238106Sdes	return 1;
853238106Sdes#else /* not HAVE_GLOB */
854238106Sdes	return anchor_read_bind_file(anchors, buffer, pat);
855238106Sdes#endif /* HAVE_GLOB */
856238106Sdes}
857238106Sdes
858238106Sdes/**
859238106Sdes * Assemble an rrset structure for the type
860238106Sdes * @param ta: trust anchor.
861238106Sdes * @param num: number of items to fetch from list.
862238106Sdes * @param type: fetch only items of this type.
863238106Sdes * @return rrset or NULL on error.
864238106Sdes */
865238106Sdesstatic struct ub_packed_rrset_key*
866238106Sdesassemble_it(struct trust_anchor* ta, size_t num, uint16_t type)
867238106Sdes{
868238106Sdes	struct ub_packed_rrset_key* pkey = (struct ub_packed_rrset_key*)
869238106Sdes		malloc(sizeof(*pkey));
870238106Sdes	struct packed_rrset_data* pd;
871238106Sdes	struct ta_key* tk;
872238106Sdes	size_t i;
873238106Sdes	if(!pkey)
874238106Sdes		return NULL;
875238106Sdes	memset(pkey, 0, sizeof(*pkey));
876238106Sdes	pkey->rk.dname = memdup(ta->name, ta->namelen);
877238106Sdes	if(!pkey->rk.dname) {
878238106Sdes		free(pkey);
879238106Sdes		return NULL;
880238106Sdes	}
881238106Sdes
882238106Sdes	pkey->rk.dname_len = ta->namelen;
883238106Sdes	pkey->rk.type = htons(type);
884238106Sdes	pkey->rk.rrset_class = htons(ta->dclass);
885238106Sdes	/* The rrset is build in an uncompressed way. This means it
886238106Sdes	 * cannot be copied in the normal way. */
887238106Sdes	pd = (struct packed_rrset_data*)malloc(sizeof(*pd));
888238106Sdes	if(!pd) {
889238106Sdes		free(pkey->rk.dname);
890238106Sdes		free(pkey);
891238106Sdes		return NULL;
892238106Sdes	}
893238106Sdes	memset(pd, 0, sizeof(*pd));
894238106Sdes	pd->count = num;
895238106Sdes	pd->trust = rrset_trust_ultimate;
896238106Sdes	pd->rr_len = (size_t*)malloc(num*sizeof(size_t));
897238106Sdes	if(!pd->rr_len) {
898238106Sdes		free(pd);
899238106Sdes		free(pkey->rk.dname);
900238106Sdes		free(pkey);
901238106Sdes		return NULL;
902238106Sdes	}
903238106Sdes	pd->rr_ttl = (uint32_t*)malloc(num*sizeof(uint32_t));
904238106Sdes	if(!pd->rr_ttl) {
905238106Sdes		free(pd->rr_len);
906238106Sdes		free(pd);
907238106Sdes		free(pkey->rk.dname);
908238106Sdes		free(pkey);
909238106Sdes		return NULL;
910238106Sdes	}
911238106Sdes	pd->rr_data = (uint8_t**)malloc(num*sizeof(uint8_t*));
912238106Sdes	if(!pd->rr_data) {
913238106Sdes		free(pd->rr_ttl);
914238106Sdes		free(pd->rr_len);
915238106Sdes		free(pd);
916238106Sdes		free(pkey->rk.dname);
917238106Sdes		free(pkey);
918238106Sdes		return NULL;
919238106Sdes	}
920238106Sdes	/* fill in rrs */
921238106Sdes	i=0;
922238106Sdes	for(tk = ta->keylist; tk; tk = tk->next) {
923238106Sdes		if(tk->type != type)
924238106Sdes			continue;
925238106Sdes		pd->rr_len[i] = tk->len;
926238106Sdes		/* reuse data ptr to allocation in talist */
927238106Sdes		pd->rr_data[i] = tk->data;
928238106Sdes		pd->rr_ttl[i] = 0;
929238106Sdes		i++;
930238106Sdes	}
931238106Sdes	pkey->entry.data = (void*)pd;
932238106Sdes	return pkey;
933238106Sdes}
934238106Sdes
935238106Sdes/**
936238106Sdes * Assemble structures for the trust DS and DNSKEY rrsets.
937238106Sdes * @param ta: trust anchor
938238106Sdes * @return: false on error.
939238106Sdes */
940238106Sdesstatic int
941238106Sdesanchors_assemble(struct trust_anchor* ta)
942238106Sdes{
943238106Sdes	if(ta->numDS > 0) {
944238106Sdes		ta->ds_rrset = assemble_it(ta, ta->numDS, LDNS_RR_TYPE_DS);
945238106Sdes		if(!ta->ds_rrset)
946238106Sdes			return 0;
947238106Sdes	}
948238106Sdes	if(ta->numDNSKEY > 0) {
949238106Sdes		ta->dnskey_rrset = assemble_it(ta, ta->numDNSKEY,
950238106Sdes			LDNS_RR_TYPE_DNSKEY);
951238106Sdes		if(!ta->dnskey_rrset)
952238106Sdes			return 0;
953238106Sdes	}
954238106Sdes	return 1;
955238106Sdes}
956238106Sdes
957238106Sdes/**
958238106Sdes * Check DS algos for support, warn if not.
959238106Sdes * @param ta: trust anchor
960238106Sdes * @return number of DS anchors with unsupported algorithms.
961238106Sdes */
962238106Sdesstatic size_t
963238106Sdesanchors_ds_unsupported(struct trust_anchor* ta)
964238106Sdes{
965238106Sdes	size_t i, num = 0;
966238106Sdes	for(i=0; i<ta->numDS; i++) {
967238106Sdes		if(!ds_digest_algo_is_supported(ta->ds_rrset, i) ||
968238106Sdes			!ds_key_algo_is_supported(ta->ds_rrset, i))
969238106Sdes			num++;
970238106Sdes	}
971238106Sdes	return num;
972238106Sdes}
973238106Sdes
974238106Sdes/**
975238106Sdes * Check DNSKEY algos for support, warn if not.
976238106Sdes * @param ta: trust anchor
977238106Sdes * @return number of DNSKEY anchors with unsupported algorithms.
978238106Sdes */
979238106Sdesstatic size_t
980238106Sdesanchors_dnskey_unsupported(struct trust_anchor* ta)
981238106Sdes{
982238106Sdes	size_t i, num = 0;
983238106Sdes	for(i=0; i<ta->numDNSKEY; i++) {
984238106Sdes		if(!dnskey_algo_is_supported(ta->dnskey_rrset, i))
985238106Sdes			num++;
986238106Sdes	}
987238106Sdes	return num;
988238106Sdes}
989238106Sdes
990238106Sdes/**
991238106Sdes * Assemble the rrsets in the anchors, ready for use by validator.
992238106Sdes * @param anchors: trust anchor storage.
993238106Sdes * @return: false on error.
994238106Sdes */
995238106Sdesstatic int
996238106Sdesanchors_assemble_rrsets(struct val_anchors* anchors)
997238106Sdes{
998238106Sdes	struct trust_anchor* ta;
999238106Sdes	struct trust_anchor* next;
1000238106Sdes	size_t nods, nokey;
1001238106Sdes	lock_basic_lock(&anchors->lock);
1002238106Sdes	ta=(struct trust_anchor*)rbtree_first(anchors->tree);
1003238106Sdes	while((rbnode_t*)ta != RBTREE_NULL) {
1004238106Sdes		next = (struct trust_anchor*)rbtree_next(&ta->node);
1005238106Sdes		lock_basic_lock(&ta->lock);
1006238106Sdes		if(ta->autr || (ta->numDS == 0 && ta->numDNSKEY == 0)) {
1007238106Sdes			lock_basic_unlock(&ta->lock);
1008238106Sdes			ta = next; /* skip */
1009238106Sdes			continue;
1010238106Sdes		}
1011238106Sdes		if(!anchors_assemble(ta)) {
1012238106Sdes			log_err("out of memory");
1013238106Sdes			lock_basic_unlock(&ta->lock);
1014238106Sdes			lock_basic_unlock(&anchors->lock);
1015238106Sdes			return 0;
1016238106Sdes		}
1017238106Sdes		nods = anchors_ds_unsupported(ta);
1018238106Sdes		nokey = anchors_dnskey_unsupported(ta);
1019238106Sdes		if(nods) {
1020238106Sdes			log_nametypeclass(0, "warning: unsupported "
1021238106Sdes				"algorithm for trust anchor",
1022238106Sdes				ta->name, LDNS_RR_TYPE_DS, ta->dclass);
1023238106Sdes		}
1024238106Sdes		if(nokey) {
1025238106Sdes			log_nametypeclass(0, "warning: unsupported "
1026238106Sdes				"algorithm for trust anchor",
1027238106Sdes				ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
1028238106Sdes		}
1029238106Sdes		if(nods == ta->numDS && nokey == ta->numDNSKEY) {
1030238106Sdes			char b[257];
1031238106Sdes			dname_str(ta->name, b);
1032238106Sdes			log_warn("trust anchor %s has no supported algorithms,"
1033238106Sdes				" the anchor is ignored (check if you need to"
1034238106Sdes				" upgrade unbound and openssl)", b);
1035238106Sdes			(void)rbtree_delete(anchors->tree, &ta->node);
1036238106Sdes			lock_basic_unlock(&ta->lock);
1037238106Sdes			anchors_delfunc(&ta->node, NULL);
1038238106Sdes			ta = next;
1039238106Sdes			continue;
1040238106Sdes		}
1041238106Sdes		lock_basic_unlock(&ta->lock);
1042238106Sdes		ta = next;
1043238106Sdes	}
1044238106Sdes	lock_basic_unlock(&anchors->lock);
1045238106Sdes	return 1;
1046238106Sdes}
1047238106Sdes
1048238106Sdesint
1049238106Sdesanchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
1050238106Sdes{
1051238106Sdes	struct config_strlist* f;
1052238106Sdes	char* nm;
1053238106Sdes	ldns_buffer* parsebuf = ldns_buffer_new(65535);
1054238106Sdes	for(f = cfg->domain_insecure; f; f = f->next) {
1055238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1056238106Sdes			continue;
1057238106Sdes		if(!anchor_insert_insecure(anchors, f->str)) {
1058238106Sdes			log_err("error in domain-insecure: %s", f->str);
1059238106Sdes			ldns_buffer_free(parsebuf);
1060238106Sdes			return 0;
1061238106Sdes		}
1062238106Sdes	}
1063238106Sdes	for(f = cfg->trust_anchor_file_list; f; f = f->next) {
1064238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1065238106Sdes			continue;
1066238106Sdes		nm = f->str;
1067238106Sdes		if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1068238106Sdes			cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1069238106Sdes			nm += strlen(cfg->chrootdir);
1070238106Sdes		if(!anchor_read_file(anchors, parsebuf, nm, 0)) {
1071238106Sdes			log_err("error reading trust-anchor-file: %s", f->str);
1072238106Sdes			ldns_buffer_free(parsebuf);
1073238106Sdes			return 0;
1074238106Sdes		}
1075238106Sdes	}
1076238106Sdes	for(f = cfg->trusted_keys_file_list; f; f = f->next) {
1077238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1078238106Sdes			continue;
1079238106Sdes		nm = f->str;
1080238106Sdes		if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1081238106Sdes			cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1082238106Sdes			nm += strlen(cfg->chrootdir);
1083238106Sdes		if(!anchor_read_bind_file_wild(anchors, parsebuf, nm)) {
1084238106Sdes			log_err("error reading trusted-keys-file: %s", f->str);
1085238106Sdes			ldns_buffer_free(parsebuf);
1086238106Sdes			return 0;
1087238106Sdes		}
1088238106Sdes	}
1089238106Sdes	for(f = cfg->trust_anchor_list; f; f = f->next) {
1090238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1091238106Sdes			continue;
1092238106Sdes		if(!anchor_store_str(anchors, parsebuf, f->str)) {
1093238106Sdes			log_err("error in trust-anchor: \"%s\"", f->str);
1094238106Sdes			ldns_buffer_free(parsebuf);
1095238106Sdes			return 0;
1096238106Sdes		}
1097238106Sdes	}
1098238106Sdes	if(cfg->dlv_anchor_file && cfg->dlv_anchor_file[0] != 0) {
1099238106Sdes		struct trust_anchor* dlva;
1100238106Sdes		nm = cfg->dlv_anchor_file;
1101238106Sdes		if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1102238106Sdes			cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1103238106Sdes			nm += strlen(cfg->chrootdir);
1104238106Sdes		if(!(dlva = anchor_read_file(anchors, parsebuf,
1105238106Sdes			nm, 1))) {
1106238106Sdes			log_err("error reading dlv-anchor-file: %s",
1107238106Sdes				cfg->dlv_anchor_file);
1108238106Sdes			ldns_buffer_free(parsebuf);
1109238106Sdes			return 0;
1110238106Sdes		}
1111238106Sdes		lock_basic_lock(&anchors->lock);
1112238106Sdes		anchors->dlv_anchor = dlva;
1113238106Sdes		lock_basic_unlock(&anchors->lock);
1114238106Sdes	}
1115238106Sdes	for(f = cfg->dlv_anchor_list; f; f = f->next) {
1116238106Sdes		struct trust_anchor* dlva;
1117238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1118238106Sdes			continue;
1119238106Sdes		if(!(dlva = anchor_store_str(
1120238106Sdes			anchors, parsebuf, f->str))) {
1121238106Sdes			log_err("error in dlv-anchor: \"%s\"", f->str);
1122238106Sdes			ldns_buffer_free(parsebuf);
1123238106Sdes			return 0;
1124238106Sdes		}
1125238106Sdes		lock_basic_lock(&anchors->lock);
1126238106Sdes		anchors->dlv_anchor = dlva;
1127238106Sdes		lock_basic_unlock(&anchors->lock);
1128238106Sdes	}
1129238106Sdes	/* do autr last, so that it sees what anchors are filled by other
1130238106Sdes	 * means can can print errors about double config for the name */
1131238106Sdes	for(f = cfg->auto_trust_anchor_file_list; f; f = f->next) {
1132238106Sdes		if(!f->str || f->str[0] == 0) /* empty "" */
1133238106Sdes			continue;
1134238106Sdes		nm = f->str;
1135238106Sdes		if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1136238106Sdes			cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1137238106Sdes			nm += strlen(cfg->chrootdir);
1138238106Sdes		if(!autr_read_file(anchors, nm)) {
1139238106Sdes			log_err("error reading auto-trust-anchor-file: %s",
1140238106Sdes				f->str);
1141238106Sdes			ldns_buffer_free(parsebuf);
1142238106Sdes			return 0;
1143238106Sdes		}
1144238106Sdes	}
1145238106Sdes	/* first assemble, since it may delete useless anchors */
1146238106Sdes	anchors_assemble_rrsets(anchors);
1147238106Sdes	init_parents(anchors);
1148238106Sdes	ldns_buffer_free(parsebuf);
1149238106Sdes	if(verbosity >= VERB_ALGO) autr_debug_print(anchors);
1150238106Sdes	return 1;
1151238106Sdes}
1152238106Sdes
1153238106Sdesstruct trust_anchor*
1154238106Sdesanchors_lookup(struct val_anchors* anchors,
1155238106Sdes        uint8_t* qname, size_t qname_len, uint16_t qclass)
1156238106Sdes{
1157238106Sdes	struct trust_anchor key;
1158238106Sdes	struct trust_anchor* result;
1159238106Sdes	rbnode_t* res = NULL;
1160238106Sdes	key.node.key = &key;
1161238106Sdes	key.name = qname;
1162238106Sdes	key.namelabs = dname_count_labels(qname);
1163238106Sdes	key.namelen = qname_len;
1164238106Sdes	key.dclass = qclass;
1165238106Sdes	lock_basic_lock(&anchors->lock);
1166238106Sdes	if(rbtree_find_less_equal(anchors->tree, &key, &res)) {
1167238106Sdes		/* exact */
1168238106Sdes		result = (struct trust_anchor*)res;
1169238106Sdes	} else {
1170238106Sdes		/* smaller element (or no element) */
1171238106Sdes		int m;
1172238106Sdes		result = (struct trust_anchor*)res;
1173238106Sdes		if(!result || result->dclass != qclass) {
1174238106Sdes			lock_basic_unlock(&anchors->lock);
1175238106Sdes			return NULL;
1176238106Sdes		}
1177238106Sdes		/* count number of labels matched */
1178238106Sdes		(void)dname_lab_cmp(result->name, result->namelabs, key.name,
1179238106Sdes			key.namelabs, &m);
1180238106Sdes		while(result) { /* go up until qname is subdomain of stub */
1181238106Sdes			if(result->namelabs <= m)
1182238106Sdes				break;
1183238106Sdes			result = result->parent;
1184238106Sdes		}
1185238106Sdes	}
1186238106Sdes	if(result) {
1187238106Sdes		lock_basic_lock(&result->lock);
1188238106Sdes	}
1189238106Sdes	lock_basic_unlock(&anchors->lock);
1190238106Sdes	return result;
1191238106Sdes}
1192238106Sdes
1193238106Sdessize_t
1194238106Sdesanchors_get_mem(struct val_anchors* anchors)
1195238106Sdes{
1196238106Sdes	struct trust_anchor *ta;
1197238106Sdes	size_t s = sizeof(*anchors);
1198238106Sdes	RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) {
1199238106Sdes		s += sizeof(*ta) + ta->namelen;
1200238106Sdes		/* keys and so on */
1201238106Sdes	}
1202238106Sdes	return s;
1203238106Sdes}
1204238106Sdes
1205238106Sdesint
1206238106Sdesanchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm)
1207238106Sdes{
1208238106Sdes	struct trust_anchor key;
1209238106Sdes	key.node.key = &key;
1210238106Sdes	key.name = nm;
1211238106Sdes	key.namelabs = dname_count_size_labels(nm, &key.namelen);
1212238106Sdes	key.dclass = c;
1213238106Sdes	lock_basic_lock(&anchors->lock);
1214238106Sdes	if(rbtree_search(anchors->tree, &key)) {
1215238106Sdes		lock_basic_unlock(&anchors->lock);
1216238106Sdes		/* nothing to do, already an anchor or insecure point */
1217238106Sdes		return 1;
1218238106Sdes	}
1219238106Sdes	if(!anchor_new_ta(anchors, nm, key.namelabs, key.namelen, c, 0)) {
1220238106Sdes		log_err("out of memory");
1221238106Sdes		lock_basic_unlock(&anchors->lock);
1222238106Sdes		return 0;
1223238106Sdes	}
1224238106Sdes	/* no other contents in new ta, because it is insecure point */
1225238106Sdes	anchors_init_parents_locked(anchors);
1226238106Sdes	lock_basic_unlock(&anchors->lock);
1227238106Sdes	return 1;
1228238106Sdes}
1229238106Sdes
1230238106Sdesvoid
1231238106Sdesanchors_delete_insecure(struct val_anchors* anchors, uint16_t c,
1232238106Sdes        uint8_t* nm)
1233238106Sdes{
1234238106Sdes	struct trust_anchor key;
1235238106Sdes	struct trust_anchor* ta;
1236238106Sdes	key.node.key = &key;
1237238106Sdes	key.name = nm;
1238238106Sdes	key.namelabs = dname_count_size_labels(nm, &key.namelen);
1239238106Sdes	key.dclass = c;
1240238106Sdes	lock_basic_lock(&anchors->lock);
1241238106Sdes	if(!(ta=(struct trust_anchor*)rbtree_search(anchors->tree, &key))) {
1242238106Sdes		lock_basic_unlock(&anchors->lock);
1243238106Sdes		/* nothing there */
1244238106Sdes		return;
1245238106Sdes	}
1246238106Sdes	/* lock it to drive away other threads that use it */
1247238106Sdes	lock_basic_lock(&ta->lock);
1248238106Sdes	/* see if its really an insecure point */
1249238106Sdes	if(ta->keylist || ta->autr || ta->numDS || ta->numDNSKEY) {
1250249141Sdes		lock_basic_unlock(&anchors->lock);
1251238106Sdes		lock_basic_unlock(&ta->lock);
1252238106Sdes		/* its not an insecure point, do not remove it */
1253238106Sdes		return;
1254238106Sdes	}
1255238106Sdes
1256238106Sdes	/* remove from tree */
1257238106Sdes	(void)rbtree_delete(anchors->tree, &ta->node);
1258238106Sdes	anchors_init_parents_locked(anchors);
1259238106Sdes	lock_basic_unlock(&anchors->lock);
1260238106Sdes
1261238106Sdes	/* actual free of data */
1262238106Sdes	lock_basic_unlock(&ta->lock);
1263238106Sdes	anchors_delfunc(&ta->node, NULL);
1264238106Sdes}
1265238106Sdes
1266