1238106Sdes/*
2238106Sdes * validator/autotrust.c - RFC5011 trust anchor management for unbound.
3238106Sdes *
4238106Sdes * Copyright (c) 2009, 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 * Contains autotrust implementation. The implementation was taken from
40238106Sdes * the autotrust daemon (BSD licensed), written by Matthijs Mekking.
41238106Sdes * It was modified to fit into unbound. The state table process is the same.
42238106Sdes */
43238106Sdes#include "config.h"
44238106Sdes#include <ldns/ldns.h>
45238106Sdes#include "validator/autotrust.h"
46238106Sdes#include "validator/val_anchor.h"
47238106Sdes#include "validator/val_utils.h"
48238106Sdes#include "validator/val_sigcrypt.h"
49238106Sdes#include "util/data/dname.h"
50238106Sdes#include "util/data/packed_rrset.h"
51238106Sdes#include "util/log.h"
52238106Sdes#include "util/module.h"
53238106Sdes#include "util/net_help.h"
54238106Sdes#include "util/config_file.h"
55238106Sdes#include "util/regional.h"
56238106Sdes#include "util/random.h"
57238106Sdes#include "util/data/msgparse.h"
58238106Sdes#include "services/mesh.h"
59238106Sdes#include "services/cache/rrset.h"
60238106Sdes#include "validator/val_kcache.h"
61238106Sdes
62238106Sdes/** number of times a key must be seen before it can become valid */
63238106Sdes#define MIN_PENDINGCOUNT 2
64238106Sdes
65238106Sdes/** Event: Revoked */
66238106Sdesstatic void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c);
67238106Sdes
68238106Sdesstruct autr_global_data* autr_global_create(void)
69238106Sdes{
70238106Sdes	struct autr_global_data* global;
71238106Sdes	global = (struct autr_global_data*)malloc(sizeof(*global));
72238106Sdes	if(!global)
73238106Sdes		return NULL;
74238106Sdes	rbtree_init(&global->probe, &probetree_cmp);
75238106Sdes	return global;
76238106Sdes}
77238106Sdes
78238106Sdesvoid autr_global_delete(struct autr_global_data* global)
79238106Sdes{
80238106Sdes	if(!global)
81238106Sdes		return;
82238106Sdes	/* elements deleted by parent */
83238106Sdes	memset(global, 0, sizeof(*global));
84238106Sdes	free(global);
85238106Sdes}
86238106Sdes
87238106Sdesint probetree_cmp(const void* x, const void* y)
88238106Sdes{
89238106Sdes	struct trust_anchor* a = (struct trust_anchor*)x;
90238106Sdes	struct trust_anchor* b = (struct trust_anchor*)y;
91238106Sdes	log_assert(a->autr && b->autr);
92238106Sdes	if(a->autr->next_probe_time < b->autr->next_probe_time)
93238106Sdes		return -1;
94238106Sdes	if(a->autr->next_probe_time > b->autr->next_probe_time)
95238106Sdes		return 1;
96238106Sdes	/* time is equal, sort on trust point identity */
97238106Sdes	return anchor_cmp(x, y);
98238106Sdes}
99238106Sdes
100238106Sdessize_t
101238106Sdesautr_get_num_anchors(struct val_anchors* anchors)
102238106Sdes{
103238106Sdes	size_t res = 0;
104238106Sdes	if(!anchors)
105238106Sdes		return 0;
106238106Sdes	lock_basic_lock(&anchors->lock);
107238106Sdes	if(anchors->autr)
108238106Sdes		res = anchors->autr->probe.count;
109238106Sdes	lock_basic_unlock(&anchors->lock);
110238106Sdes	return res;
111238106Sdes}
112238106Sdes
113238106Sdes/** Position in string */
114238106Sdesstatic int
115238106Sdesposition_in_string(char *str, const char* sub)
116238106Sdes{
117238106Sdes	char* pos = strstr(str, sub);
118238106Sdes	if(pos)
119238106Sdes		return (int)(pos-str)+(int)strlen(sub);
120238106Sdes	return -1;
121238106Sdes}
122238106Sdes
123238106Sdes/** Debug routine to print pretty key information */
124238106Sdesstatic void
125238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level,
126238106Sdes	const char* format, ...) ATTR_FORMAT(printf, 3, 4);
127238106Sdes
128238106Sdes/**
129238106Sdes * Implementation of debug pretty key print
130238106Sdes * @param ta: trust anchor key with DNSKEY data.
131238106Sdes * @param level: verbosity level to print at.
132238106Sdes * @param format: printf style format string.
133238106Sdes */
134238106Sdesstatic void
135238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level,
136238106Sdes	const char* format, ...)
137238106Sdes{
138238106Sdes	va_list args;
139238106Sdes	va_start(args, format);
140238106Sdes	if(verbosity >= level) {
141238106Sdes		char* str = ldns_rdf2str(ldns_rr_owner(ta->rr));
142238106Sdes		int keytag = (int)ldns_calc_keytag(ta->rr);
143238106Sdes		char msg[MAXSYSLOGMSGLEN];
144238106Sdes		vsnprintf(msg, sizeof(msg), format, args);
145238106Sdes		verbose(level, "%s key %d %s", str?str:"??", keytag, msg);
146238106Sdes		free(str);
147238106Sdes	}
148238106Sdes	va_end(args);
149238106Sdes}
150238106Sdes
151238106Sdes/**
152238106Sdes * Parse comments
153238106Sdes * @param str: to parse
154238106Sdes * @param ta: trust key autotrust metadata
155238106Sdes * @return false on failure.
156238106Sdes */
157238106Sdesstatic int
158238106Sdesparse_comments(char* str, struct autr_ta* ta)
159238106Sdes{
160238106Sdes        int len = (int)strlen(str), pos = 0, timestamp = 0;
161238106Sdes        char* comment = (char*) malloc(sizeof(char)*len+1);
162238106Sdes        char* comments = comment;
163238106Sdes	if(!comment) {
164238106Sdes		log_err("malloc failure in parse");
165238106Sdes                return 0;
166238106Sdes	}
167238106Sdes	/* skip over whitespace and data at start of line */
168238106Sdes        while (*str != '\0' && *str != ';')
169238106Sdes                str++;
170238106Sdes        if (*str == ';')
171238106Sdes                str++;
172238106Sdes        /* copy comments */
173238106Sdes        while (*str != '\0')
174238106Sdes        {
175238106Sdes                *comments = *str;
176238106Sdes                comments++;
177238106Sdes                str++;
178238106Sdes        }
179238106Sdes        *comments = '\0';
180238106Sdes
181238106Sdes        comments = comment;
182238106Sdes
183238106Sdes        /* read state */
184238106Sdes        pos = position_in_string(comments, "state=");
185238106Sdes        if (pos >= (int) strlen(comments))
186238106Sdes        {
187238106Sdes		log_err("parse error");
188238106Sdes                free(comment);
189238106Sdes                return 0;
190238106Sdes        }
191238106Sdes        if (pos <= 0)
192238106Sdes                ta->s = AUTR_STATE_VALID;
193238106Sdes        else
194238106Sdes        {
195238106Sdes                int s = (int) comments[pos] - '0';
196238106Sdes                switch(s)
197238106Sdes                {
198238106Sdes                        case AUTR_STATE_START:
199238106Sdes                        case AUTR_STATE_ADDPEND:
200238106Sdes                        case AUTR_STATE_VALID:
201238106Sdes                        case AUTR_STATE_MISSING:
202238106Sdes                        case AUTR_STATE_REVOKED:
203238106Sdes                        case AUTR_STATE_REMOVED:
204238106Sdes                                ta->s = s;
205238106Sdes                                break;
206238106Sdes                        default:
207238106Sdes				verbose_key(ta, VERB_OPS, "has undefined "
208238106Sdes					"state, considered NewKey");
209238106Sdes                                ta->s = AUTR_STATE_START;
210238106Sdes                                break;
211238106Sdes                }
212238106Sdes        }
213238106Sdes        /* read pending count */
214238106Sdes        pos = position_in_string(comments, "count=");
215238106Sdes        if (pos >= (int) strlen(comments))
216238106Sdes        {
217238106Sdes		log_err("parse error");
218238106Sdes                free(comment);
219238106Sdes                return 0;
220238106Sdes        }
221238106Sdes        if (pos <= 0)
222238106Sdes                ta->pending_count = 0;
223238106Sdes        else
224238106Sdes        {
225238106Sdes                comments += pos;
226238106Sdes                ta->pending_count = (uint8_t)atoi(comments);
227238106Sdes        }
228238106Sdes
229238106Sdes        /* read last change */
230238106Sdes        pos = position_in_string(comments, "lastchange=");
231238106Sdes        if (pos >= (int) strlen(comments))
232238106Sdes        {
233238106Sdes		log_err("parse error");
234238106Sdes                free(comment);
235238106Sdes                return 0;
236238106Sdes        }
237238106Sdes        if (pos >= 0)
238238106Sdes        {
239238106Sdes                comments += pos;
240238106Sdes                timestamp = atoi(comments);
241238106Sdes        }
242238106Sdes        if (pos < 0 || !timestamp)
243238106Sdes		ta->last_change = 0;
244238106Sdes        else
245238106Sdes                ta->last_change = (uint32_t)timestamp;
246238106Sdes
247238106Sdes        free(comment);
248238106Sdes        return 1;
249238106Sdes}
250238106Sdes
251238106Sdes/** Check if a line contains data (besides comments) */
252238106Sdesstatic int
253238106Sdesstr_contains_data(char* str, char comment)
254238106Sdes{
255238106Sdes        while (*str != '\0') {
256238106Sdes                if (*str == comment || *str == '\n')
257238106Sdes                        return 0;
258238106Sdes                if (*str != ' ' && *str != '\t')
259238106Sdes                        return 1;
260238106Sdes                str++;
261238106Sdes        }
262238106Sdes        return 0;
263238106Sdes}
264238106Sdes
265238106Sdes/** Get DNSKEY flags */
266238106Sdesstatic int
267238106Sdesdnskey_flags(ldns_rr* rr)
268238106Sdes{
269238106Sdes	if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)
270238106Sdes		return 0;
271238106Sdes	return (int)ldns_read_uint16(ldns_rdf_data(ldns_rr_dnskey_flags(rr)));
272238106Sdes}
273238106Sdes
274238106Sdes
275238106Sdes/** Check if KSK DNSKEY */
276238106Sdesstatic int
277238106Sdesrr_is_dnskey_sep(ldns_rr* rr)
278238106Sdes{
279238106Sdes	return (dnskey_flags(rr)&DNSKEY_BIT_SEP);
280238106Sdes}
281238106Sdes
282238106Sdes/** Check if REVOKED DNSKEY */
283238106Sdesstatic int
284238106Sdesrr_is_dnskey_revoked(ldns_rr* rr)
285238106Sdes{
286238106Sdes	return (dnskey_flags(rr)&LDNS_KEY_REVOKE_KEY);
287238106Sdes}
288238106Sdes
289238106Sdes/** create ta */
290238106Sdesstatic struct autr_ta*
291238106Sdesautr_ta_create(ldns_rr* rr)
292238106Sdes{
293238106Sdes	struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta));
294238106Sdes	if(!ta) {
295238106Sdes		ldns_rr_free(rr);
296238106Sdes		return NULL;
297238106Sdes	}
298238106Sdes	ta->rr = rr;
299238106Sdes	return ta;
300238106Sdes}
301238106Sdes
302238106Sdes/** create tp */
303238106Sdesstatic struct trust_anchor*
304238106Sdesautr_tp_create(struct val_anchors* anchors, ldns_rdf* own, uint16_t dc)
305238106Sdes{
306238106Sdes	struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp));
307238106Sdes	if(!tp) return NULL;
308238106Sdes	tp->name = memdup(ldns_rdf_data(own), ldns_rdf_size(own));
309238106Sdes	if(!tp->name) {
310238106Sdes		free(tp);
311238106Sdes		return NULL;
312238106Sdes	}
313238106Sdes	tp->namelen = ldns_rdf_size(own);
314238106Sdes	tp->namelabs = dname_count_labels(tp->name);
315238106Sdes	tp->node.key = tp;
316238106Sdes	tp->dclass = dc;
317238106Sdes	tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr));
318238106Sdes	if(!tp->autr) {
319238106Sdes		free(tp->name);
320238106Sdes		free(tp);
321238106Sdes		return NULL;
322238106Sdes	}
323238106Sdes	tp->autr->pnode.key = tp;
324238106Sdes
325238106Sdes	lock_basic_lock(&anchors->lock);
326238106Sdes	if(!rbtree_insert(anchors->tree, &tp->node)) {
327238106Sdes		lock_basic_unlock(&anchors->lock);
328238106Sdes		log_err("trust anchor presented twice");
329238106Sdes		free(tp->name);
330238106Sdes		free(tp->autr);
331238106Sdes		free(tp);
332238106Sdes		return NULL;
333238106Sdes	}
334238106Sdes	if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) {
335238106Sdes		(void)rbtree_delete(anchors->tree, tp);
336238106Sdes		lock_basic_unlock(&anchors->lock);
337238106Sdes		log_err("trust anchor in probetree twice");
338238106Sdes		free(tp->name);
339238106Sdes		free(tp->autr);
340238106Sdes		free(tp);
341238106Sdes		return NULL;
342238106Sdes	}
343238106Sdes	lock_basic_unlock(&anchors->lock);
344238106Sdes	lock_basic_init(&tp->lock);
345238106Sdes	lock_protect(&tp->lock, tp, sizeof(*tp));
346238106Sdes	lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
347238106Sdes	return tp;
348238106Sdes}
349238106Sdes
350238106Sdes/** delete assembled rrsets */
351238106Sdesstatic void
352238106Sdesautr_rrset_delete(struct ub_packed_rrset_key* r)
353238106Sdes{
354238106Sdes	if(r) {
355238106Sdes		free(r->rk.dname);
356238106Sdes		free(r->entry.data);
357238106Sdes		free(r);
358238106Sdes	}
359238106Sdes}
360238106Sdes
361238106Sdesvoid autr_point_delete(struct trust_anchor* tp)
362238106Sdes{
363238106Sdes	if(!tp)
364238106Sdes		return;
365238106Sdes	lock_unprotect(&tp->lock, tp);
366238106Sdes	lock_unprotect(&tp->lock, tp->autr);
367238106Sdes	lock_basic_destroy(&tp->lock);
368238106Sdes	autr_rrset_delete(tp->ds_rrset);
369238106Sdes	autr_rrset_delete(tp->dnskey_rrset);
370238106Sdes	if(tp->autr) {
371238106Sdes		struct autr_ta* p = tp->autr->keys, *np;
372238106Sdes		while(p) {
373238106Sdes			np = p->next;
374238106Sdes			ldns_rr_free(p->rr);
375238106Sdes			free(p);
376238106Sdes			p = np;
377238106Sdes		}
378238106Sdes		free(tp->autr->file);
379238106Sdes		free(tp->autr);
380238106Sdes	}
381238106Sdes	free(tp->name);
382238106Sdes	free(tp);
383238106Sdes}
384238106Sdes
385238106Sdes/** find or add a new trust point for autotrust */
386238106Sdesstatic struct trust_anchor*
387238106Sdesfind_add_tp(struct val_anchors* anchors, ldns_rr* rr)
388238106Sdes{
389238106Sdes	struct trust_anchor* tp;
390238106Sdes	ldns_rdf* own = ldns_rr_owner(rr);
391238106Sdes	tp = anchor_find(anchors, ldns_rdf_data(own),
392238106Sdes		dname_count_labels(ldns_rdf_data(own)),
393238106Sdes		ldns_rdf_size(own), ldns_rr_get_class(rr));
394238106Sdes	if(tp) {
395238106Sdes		if(!tp->autr) {
396238106Sdes			log_err("anchor cannot be with and without autotrust");
397238106Sdes			lock_basic_unlock(&tp->lock);
398238106Sdes			return NULL;
399238106Sdes		}
400238106Sdes		return tp;
401238106Sdes	}
402238106Sdes	tp = autr_tp_create(anchors, ldns_rr_owner(rr), ldns_rr_get_class(rr));
403238106Sdes	lock_basic_lock(&tp->lock);
404238106Sdes	return tp;
405238106Sdes}
406238106Sdes
407238106Sdes/** Add trust anchor from RR */
408238106Sdesstatic struct autr_ta*
409238106Sdesadd_trustanchor_frm_rr(struct val_anchors* anchors, ldns_rr* rr,
410238106Sdes	struct trust_anchor** tp)
411238106Sdes{
412238106Sdes	struct autr_ta* ta = autr_ta_create(rr);
413238106Sdes	if(!ta)
414238106Sdes		return NULL;
415238106Sdes	*tp = find_add_tp(anchors, rr);
416238106Sdes	if(!*tp) {
417238106Sdes		ldns_rr_free(ta->rr);
418238106Sdes		free(ta);
419238106Sdes		return NULL;
420238106Sdes	}
421238106Sdes	/* add ta to tp */
422238106Sdes	ta->next = (*tp)->autr->keys;
423238106Sdes	(*tp)->autr->keys = ta;
424238106Sdes	lock_basic_unlock(&(*tp)->lock);
425238106Sdes	return ta;
426238106Sdes}
427238106Sdes
428238106Sdes/**
429238106Sdes * Add new trust anchor from a string in file.
430238106Sdes * @param anchors: all anchors
431238106Sdes * @param str: string with anchor and comments, if any comments.
432238106Sdes * @param tp: trust point returned.
433238106Sdes * @param origin: what to use for @
434238106Sdes * @param prev: previous rr name
435238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it.
436238106Sdes * @return new key in trust point.
437238106Sdes */
438238106Sdesstatic struct autr_ta*
439238106Sdesadd_trustanchor_frm_str(struct val_anchors* anchors, char* str,
440238106Sdes	struct trust_anchor** tp, ldns_rdf* origin, ldns_rdf** prev, int* skip)
441238106Sdes{
442238106Sdes        ldns_rr* rr;
443238106Sdes	ldns_status lstatus;
444238106Sdes        if (!str_contains_data(str, ';')) {
445238106Sdes		*skip = 1;
446238106Sdes                return NULL; /* empty line */
447238106Sdes	}
448238106Sdes        if (LDNS_STATUS_OK !=
449238106Sdes                (lstatus = ldns_rr_new_frm_str(&rr, str, 0, origin, prev)))
450238106Sdes        {
451238106Sdes        	log_err("ldns error while converting string to RR: %s",
452238106Sdes			ldns_get_errorstr_by_id(lstatus));
453238106Sdes                return NULL;
454238106Sdes        }
455238106Sdes	if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY &&
456238106Sdes		ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS) {
457238106Sdes		ldns_rr_free(rr);
458238106Sdes		*skip = 1;
459238106Sdes		return NULL; /* only DS and DNSKEY allowed */
460238106Sdes	}
461238106Sdes        return add_trustanchor_frm_rr(anchors, rr, tp);
462238106Sdes}
463238106Sdes
464238106Sdes/**
465238106Sdes * Load single anchor
466238106Sdes * @param anchors: all points.
467238106Sdes * @param str: comments line
468238106Sdes * @param fname: filename
469249141Sdes * @param origin: the $ORIGIN.
470238106Sdes * @param prev: passed to ldns.
471238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it.
472238106Sdes * @return false on failure, otherwise the tp read.
473238106Sdes */
474238106Sdesstatic struct trust_anchor*
475238106Sdesload_trustanchor(struct val_anchors* anchors, char* str, const char* fname,
476238106Sdes	ldns_rdf* origin, ldns_rdf** prev, int* skip)
477238106Sdes{
478238106Sdes        struct autr_ta* ta = NULL;
479238106Sdes        struct trust_anchor* tp = NULL;
480238106Sdes
481238106Sdes        ta = add_trustanchor_frm_str(anchors, str, &tp, origin, prev, skip);
482238106Sdes	if(!ta)
483238106Sdes		return NULL;
484238106Sdes	lock_basic_lock(&tp->lock);
485238106Sdes	if(!parse_comments(str, ta)) {
486238106Sdes		lock_basic_unlock(&tp->lock);
487238106Sdes		return NULL;
488238106Sdes	}
489238106Sdes	if(!tp->autr->file) {
490238106Sdes		tp->autr->file = strdup(fname);
491238106Sdes		if(!tp->autr->file) {
492238106Sdes			lock_basic_unlock(&tp->lock);
493238106Sdes			log_err("malloc failure");
494238106Sdes			return NULL;
495238106Sdes		}
496238106Sdes	}
497238106Sdes	lock_basic_unlock(&tp->lock);
498238106Sdes        return tp;
499238106Sdes}
500238106Sdes
501238106Sdes/**
502238106Sdes * Assemble the trust anchors into DS and DNSKEY packed rrsets.
503238106Sdes * Uses only VALID and MISSING DNSKEYs.
504238106Sdes * Read the ldns_rrs and builds packed rrsets
505238106Sdes * @param tp: the trust point. Must be locked.
506238106Sdes * @return false on malloc failure.
507238106Sdes */
508238106Sdesstatic int
509238106Sdesautr_assemble(struct trust_anchor* tp)
510238106Sdes{
511238106Sdes	ldns_rr_list* ds, *dnskey;
512238106Sdes	struct autr_ta* ta;
513238106Sdes	struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL;
514238106Sdes
515238106Sdes	ds = ldns_rr_list_new();
516238106Sdes	dnskey = ldns_rr_list_new();
517238106Sdes	if(!ds || !dnskey) {
518238106Sdes		ldns_rr_list_free(ds);
519238106Sdes		ldns_rr_list_free(dnskey);
520238106Sdes		return 0;
521238106Sdes	}
522238106Sdes	for(ta = tp->autr->keys; ta; ta = ta->next) {
523238106Sdes		if(ldns_rr_get_type(ta->rr) == LDNS_RR_TYPE_DS) {
524238106Sdes			if(!ldns_rr_list_push_rr(ds, ta->rr)) {
525238106Sdes				ldns_rr_list_free(ds);
526238106Sdes				ldns_rr_list_free(dnskey);
527238106Sdes				return 0;
528238106Sdes			}
529238106Sdes		} else if(ta->s == AUTR_STATE_VALID ||
530238106Sdes			ta->s == AUTR_STATE_MISSING) {
531238106Sdes			if(!ldns_rr_list_push_rr(dnskey, ta->rr)) {
532238106Sdes				ldns_rr_list_free(ds);
533238106Sdes				ldns_rr_list_free(dnskey);
534238106Sdes				return 0;
535238106Sdes			}
536238106Sdes		}
537238106Sdes	}
538238106Sdes
539238106Sdes	/* make packed rrset keys - malloced with no ID number, they
540238106Sdes	 * are not in the cache */
541238106Sdes	/* make packed rrset data (if there is a key) */
542238106Sdes
543238106Sdes	if(ldns_rr_list_rr_count(ds) > 0) {
544238106Sdes		ubds = ub_packed_rrset_heap_key(ds);
545238106Sdes		if(!ubds)
546238106Sdes			goto error_cleanup;
547238106Sdes		ubds->entry.data = packed_rrset_heap_data(ds);
548238106Sdes		if(!ubds->entry.data)
549238106Sdes			goto error_cleanup;
550238106Sdes	}
551238106Sdes	if(ldns_rr_list_rr_count(dnskey) > 0) {
552238106Sdes		ubdnskey = ub_packed_rrset_heap_key(dnskey);
553238106Sdes		if(!ubdnskey)
554238106Sdes			goto error_cleanup;
555238106Sdes		ubdnskey->entry.data = packed_rrset_heap_data(dnskey);
556238106Sdes		if(!ubdnskey->entry.data) {
557238106Sdes		error_cleanup:
558238106Sdes			autr_rrset_delete(ubds);
559238106Sdes			autr_rrset_delete(ubdnskey);
560238106Sdes			ldns_rr_list_free(ds);
561238106Sdes			ldns_rr_list_free(dnskey);
562238106Sdes			return 0;
563238106Sdes		}
564238106Sdes	}
565238106Sdes	/* we have prepared the new keys so nothing can go wrong any more.
566238106Sdes	 * And we are sure we cannot be left without trustanchor after
567238106Sdes	 * any errors. Put in the new keys and remove old ones. */
568238106Sdes
569238106Sdes	/* free the old data */
570238106Sdes	autr_rrset_delete(tp->ds_rrset);
571238106Sdes	autr_rrset_delete(tp->dnskey_rrset);
572238106Sdes
573238106Sdes	/* assign the data to replace the old */
574238106Sdes	tp->ds_rrset = ubds;
575238106Sdes	tp->dnskey_rrset = ubdnskey;
576238106Sdes	tp->numDS = ldns_rr_list_rr_count(ds);
577238106Sdes	tp->numDNSKEY = ldns_rr_list_rr_count(dnskey);
578238106Sdes
579238106Sdes	ldns_rr_list_free(ds);
580238106Sdes	ldns_rr_list_free(dnskey);
581238106Sdes	return 1;
582238106Sdes}
583238106Sdes
584238106Sdes/** parse integer */
585238106Sdesstatic unsigned int
586238106Sdesparse_int(char* line, int* ret)
587238106Sdes{
588238106Sdes	char *e;
589238106Sdes	unsigned int x = (unsigned int)strtol(line, &e, 10);
590238106Sdes	if(line == e) {
591238106Sdes		*ret = -1; /* parse error */
592238106Sdes		return 0;
593238106Sdes	}
594238106Sdes	*ret = 1; /* matched */
595238106Sdes	return x;
596238106Sdes}
597238106Sdes
598238106Sdes/** parse id sequence for anchor */
599238106Sdesstatic struct trust_anchor*
600238106Sdesparse_id(struct val_anchors* anchors, char* line)
601238106Sdes{
602238106Sdes	struct trust_anchor *tp;
603238106Sdes	int r;
604238106Sdes	ldns_rdf* rdf;
605238106Sdes	uint16_t dclass;
606238106Sdes	/* read the owner name */
607238106Sdes	char* next = strchr(line, ' ');
608238106Sdes	if(!next)
609238106Sdes		return NULL;
610238106Sdes	next[0] = 0;
611238106Sdes	rdf = ldns_dname_new_frm_str(line);
612238106Sdes	if(!rdf)
613238106Sdes		return NULL;
614238106Sdes
615238106Sdes	/* read the class */
616238106Sdes	dclass = parse_int(next+1, &r);
617238106Sdes	if(r == -1) {
618238106Sdes		ldns_rdf_deep_free(rdf);
619238106Sdes		return NULL;
620238106Sdes	}
621238106Sdes
622238106Sdes	/* find the trust point */
623238106Sdes	tp = autr_tp_create(anchors, rdf, dclass);
624238106Sdes	ldns_rdf_deep_free(rdf);
625238106Sdes	return tp;
626238106Sdes}
627238106Sdes
628238106Sdes/**
629238106Sdes * Parse variable from trustanchor header
630238106Sdes * @param line: to parse
631238106Sdes * @param anchors: the anchor is added to this, if "id:" is seen.
632238106Sdes * @param anchor: the anchor as result value or previously returned anchor
633238106Sdes * 	value to read the variable lines into.
634238106Sdes * @return: 0 no match, -1 failed syntax error, +1 success line read.
635238106Sdes * 	+2 revoked trust anchor file.
636238106Sdes */
637238106Sdesstatic int
638238106Sdesparse_var_line(char* line, struct val_anchors* anchors,
639238106Sdes	struct trust_anchor** anchor)
640238106Sdes{
641238106Sdes	struct trust_anchor* tp = *anchor;
642238106Sdes	int r = 0;
643238106Sdes	if(strncmp(line, ";;id: ", 6) == 0) {
644238106Sdes		*anchor = parse_id(anchors, line+6);
645238106Sdes		if(!*anchor) return -1;
646238106Sdes		else return 1;
647238106Sdes	} else if(strncmp(line, ";;REVOKED", 9) == 0) {
648238106Sdes		if(tp) {
649238106Sdes			log_err("REVOKED statement must be at start of file");
650238106Sdes			return -1;
651238106Sdes		}
652238106Sdes		return 2;
653238106Sdes	} else if(strncmp(line, ";;last_queried: ", 16) == 0) {
654238106Sdes		if(!tp) return -1;
655238106Sdes		lock_basic_lock(&tp->lock);
656238106Sdes		tp->autr->last_queried = (time_t)parse_int(line+16, &r);
657238106Sdes		lock_basic_unlock(&tp->lock);
658238106Sdes	} else if(strncmp(line, ";;last_success: ", 16) == 0) {
659238106Sdes		if(!tp) return -1;
660238106Sdes		lock_basic_lock(&tp->lock);
661238106Sdes		tp->autr->last_success = (time_t)parse_int(line+16, &r);
662238106Sdes		lock_basic_unlock(&tp->lock);
663238106Sdes	} else if(strncmp(line, ";;next_probe_time: ", 19) == 0) {
664238106Sdes		if(!tp) return -1;
665238106Sdes		lock_basic_lock(&anchors->lock);
666238106Sdes		lock_basic_lock(&tp->lock);
667238106Sdes		(void)rbtree_delete(&anchors->autr->probe, tp);
668238106Sdes		tp->autr->next_probe_time = (time_t)parse_int(line+19, &r);
669238106Sdes		(void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode);
670238106Sdes		lock_basic_unlock(&tp->lock);
671238106Sdes		lock_basic_unlock(&anchors->lock);
672238106Sdes	} else if(strncmp(line, ";;query_failed: ", 16) == 0) {
673238106Sdes		if(!tp) return -1;
674238106Sdes		lock_basic_lock(&tp->lock);
675238106Sdes		tp->autr->query_failed = (uint8_t)parse_int(line+16, &r);
676238106Sdes		lock_basic_unlock(&tp->lock);
677238106Sdes	} else if(strncmp(line, ";;query_interval: ", 18) == 0) {
678238106Sdes		if(!tp) return -1;
679238106Sdes		lock_basic_lock(&tp->lock);
680238106Sdes		tp->autr->query_interval = (uint32_t)parse_int(line+18, &r);
681238106Sdes		lock_basic_unlock(&tp->lock);
682238106Sdes	} else if(strncmp(line, ";;retry_time: ", 14) == 0) {
683238106Sdes		if(!tp) return -1;
684238106Sdes		lock_basic_lock(&tp->lock);
685238106Sdes		tp->autr->retry_time = (uint32_t)parse_int(line+14, &r);
686238106Sdes		lock_basic_unlock(&tp->lock);
687238106Sdes	}
688238106Sdes	return r;
689238106Sdes}
690238106Sdes
691238106Sdes/** handle origin lines */
692238106Sdesstatic int
693238106Sdeshandle_origin(char* line, ldns_rdf** origin)
694238106Sdes{
695238106Sdes	while(isspace((int)*line))
696238106Sdes		line++;
697238106Sdes	if(strncmp(line, "$ORIGIN", 7) != 0)
698238106Sdes		return 0;
699238106Sdes	ldns_rdf_deep_free(*origin);
700238106Sdes	line += 7;
701238106Sdes	while(isspace((int)*line))
702238106Sdes		line++;
703238106Sdes	*origin = ldns_dname_new_frm_str(line);
704238106Sdes	if(!*origin)
705238106Sdes		log_warn("malloc failure or parse error in $ORIGIN");
706238106Sdes	return 1;
707238106Sdes}
708238106Sdes
709238106Sdes/** Read one line and put multiline RRs onto one line string */
710238106Sdesstatic int
711238106Sdesread_multiline(char* buf, size_t len, FILE* in, int* linenr)
712238106Sdes{
713238106Sdes	char* pos = buf;
714238106Sdes	size_t left = len;
715238106Sdes	int depth = 0;
716238106Sdes	buf[len-1] = 0;
717238106Sdes	while(left > 0 && fgets(pos, (int)left, in) != NULL) {
718238106Sdes		size_t i, poslen = strlen(pos);
719238106Sdes		(*linenr)++;
720238106Sdes
721238106Sdes		/* check what the new depth is after the line */
722238106Sdes		/* this routine cannot handle braces inside quotes,
723238106Sdes		   say for TXT records, but this routine only has to read keys */
724238106Sdes		for(i=0; i<poslen; i++) {
725238106Sdes			if(pos[i] == '(') {
726238106Sdes				depth++;
727238106Sdes			} else if(pos[i] == ')') {
728238106Sdes				if(depth == 0) {
729238106Sdes					log_err("mismatch: too many ')'");
730238106Sdes					return -1;
731238106Sdes				}
732238106Sdes				depth--;
733238106Sdes			} else if(pos[i] == ';') {
734238106Sdes				break;
735238106Sdes			}
736238106Sdes		}
737238106Sdes
738238106Sdes		/* normal oneline or last line: keeps newline and comments */
739238106Sdes		if(depth == 0) {
740238106Sdes			return 1;
741238106Sdes		}
742238106Sdes
743238106Sdes		/* more lines expected, snip off comments and newline */
744238106Sdes		if(poslen>0)
745238106Sdes			pos[poslen-1] = 0; /* strip newline */
746238106Sdes		if(strchr(pos, ';'))
747238106Sdes			strchr(pos, ';')[0] = 0; /* strip comments */
748238106Sdes
749238106Sdes		/* move to paste other lines behind this one */
750238106Sdes		poslen = strlen(pos);
751238106Sdes		pos += poslen;
752238106Sdes		left -= poslen;
753238106Sdes		/* the newline is changed into a space */
754238106Sdes		if(left <= 2 /* space and eos */) {
755238106Sdes			log_err("line too long");
756238106Sdes			return -1;
757238106Sdes		}
758238106Sdes		pos[0] = ' ';
759238106Sdes		pos[1] = 0;
760238106Sdes		pos += 1;
761238106Sdes		left -= 1;
762238106Sdes	}
763238106Sdes	if(depth != 0) {
764238106Sdes		log_err("mismatch: too many '('");
765238106Sdes		return -1;
766238106Sdes	}
767238106Sdes	if(pos != buf)
768238106Sdes		return 1;
769238106Sdes	return 0;
770238106Sdes}
771238106Sdes
772238106Sdesint autr_read_file(struct val_anchors* anchors, const char* nm)
773238106Sdes{
774238106Sdes        /* the file descriptor */
775238106Sdes        FILE* fd;
776238106Sdes        /* keep track of line numbers */
777238106Sdes        int line_nr = 0;
778238106Sdes        /* single line */
779238106Sdes        char line[10240];
780238106Sdes	/* trust point being read */
781238106Sdes	struct trust_anchor *tp = NULL, *tp2;
782238106Sdes	int r;
783238106Sdes	/* for $ORIGIN parsing */
784238106Sdes	ldns_rdf *origin=NULL, *prev=NULL;
785238106Sdes
786238106Sdes        if (!(fd = fopen(nm, "r"))) {
787238106Sdes                log_err("unable to open %s for reading: %s",
788238106Sdes			nm, strerror(errno));
789238106Sdes                return 0;
790238106Sdes        }
791238106Sdes        verbose(VERB_ALGO, "reading autotrust anchor file %s", nm);
792238106Sdes        while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) {
793238106Sdes		if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) {
794238106Sdes			log_err("could not parse auto-trust-anchor-file "
795238106Sdes				"%s line %d", nm, line_nr);
796238106Sdes			fclose(fd);
797238106Sdes			ldns_rdf_deep_free(origin);
798238106Sdes			ldns_rdf_deep_free(prev);
799238106Sdes			return 0;
800238106Sdes		} else if(r == 1) {
801238106Sdes			continue;
802238106Sdes		} else if(r == 2) {
803238106Sdes			log_warn("trust anchor %s has been revoked", nm);
804238106Sdes			fclose(fd);
805238106Sdes			ldns_rdf_deep_free(origin);
806238106Sdes			ldns_rdf_deep_free(prev);
807238106Sdes			return 1;
808238106Sdes		}
809238106Sdes        	if (!str_contains_data(line, ';'))
810238106Sdes                	continue; /* empty lines allowed */
811238106Sdes 		if(handle_origin(line, &origin))
812238106Sdes			continue;
813238106Sdes		r = 0;
814238106Sdes                if(!(tp2=load_trustanchor(anchors, line, nm, origin, &prev,
815238106Sdes			&r))) {
816238106Sdes			if(!r) log_err("failed to load trust anchor from %s "
817238106Sdes				"at line %i, skipping", nm, line_nr);
818238106Sdes                        /* try to do the rest */
819238106Sdes			continue;
820238106Sdes                }
821238106Sdes		if(tp && tp != tp2) {
822238106Sdes			log_err("file %s has mismatching data inside: "
823238106Sdes				"the file may only contain keys for one name, "
824238106Sdes				"remove keys for other domain names", nm);
825238106Sdes        		fclose(fd);
826238106Sdes			ldns_rdf_deep_free(origin);
827238106Sdes			ldns_rdf_deep_free(prev);
828238106Sdes			return 0;
829238106Sdes		}
830238106Sdes		tp = tp2;
831238106Sdes        }
832238106Sdes        fclose(fd);
833238106Sdes	ldns_rdf_deep_free(origin);
834238106Sdes	ldns_rdf_deep_free(prev);
835238106Sdes	if(!tp) {
836238106Sdes		log_err("failed to read %s", nm);
837238106Sdes		return 0;
838238106Sdes	}
839238106Sdes
840238106Sdes	/* now assemble the data into DNSKEY and DS packed rrsets */
841238106Sdes	lock_basic_lock(&tp->lock);
842238106Sdes	if(!autr_assemble(tp)) {
843238106Sdes		lock_basic_unlock(&tp->lock);
844238106Sdes		log_err("malloc failure assembling %s", nm);
845238106Sdes		return 0;
846238106Sdes	}
847238106Sdes	lock_basic_unlock(&tp->lock);
848238106Sdes	return 1;
849238106Sdes}
850238106Sdes
851238106Sdes/** string for a trustanchor state */
852238106Sdesstatic const char*
853238106Sdestrustanchor_state2str(autr_state_t s)
854238106Sdes{
855238106Sdes        switch (s) {
856238106Sdes                case AUTR_STATE_START:       return "  START  ";
857238106Sdes                case AUTR_STATE_ADDPEND:     return " ADDPEND ";
858238106Sdes                case AUTR_STATE_VALID:       return "  VALID  ";
859238106Sdes                case AUTR_STATE_MISSING:     return " MISSING ";
860238106Sdes                case AUTR_STATE_REVOKED:     return " REVOKED ";
861238106Sdes                case AUTR_STATE_REMOVED:     return " REMOVED ";
862238106Sdes        }
863238106Sdes        return " UNKNOWN ";
864238106Sdes}
865238106Sdes
866238106Sdes/** print ID to file */
867238106Sdesstatic int
868238106Sdesprint_id(FILE* out, char* fname, struct module_env* env,
869238106Sdes	uint8_t* nm, size_t nmlen, uint16_t dclass)
870238106Sdes{
871238106Sdes	ldns_rdf rdf;
872238106Sdes#ifdef UNBOUND_DEBUG
873238106Sdes	ldns_status s;
874238106Sdes#endif
875238106Sdes
876238106Sdes	memset(&rdf, 0, sizeof(rdf));
877238106Sdes	ldns_rdf_set_data(&rdf, nm);
878238106Sdes	ldns_rdf_set_size(&rdf, nmlen);
879238106Sdes	ldns_rdf_set_type(&rdf, LDNS_RDF_TYPE_DNAME);
880238106Sdes
881238106Sdes	ldns_buffer_clear(env->scratch_buffer);
882238106Sdes#ifdef UNBOUND_DEBUG
883238106Sdes	s =
884238106Sdes#endif
885238106Sdes	ldns_rdf2buffer_str_dname(env->scratch_buffer, &rdf);
886238106Sdes	log_assert(s == LDNS_STATUS_OK);
887238106Sdes	ldns_buffer_write_u8(env->scratch_buffer, 0);
888238106Sdes	ldns_buffer_flip(env->scratch_buffer);
889238106Sdes	if(fprintf(out, ";;id: %s %d\n",
890238106Sdes		(char*)ldns_buffer_begin(env->scratch_buffer),
891238106Sdes		(int)dclass) < 0) {
892238106Sdes		log_err("could not write to %s: %s", fname, strerror(errno));
893238106Sdes		return 0;
894238106Sdes	}
895238106Sdes	return 1;
896238106Sdes}
897238106Sdes
898238106Sdesstatic int
899238106Sdesautr_write_contents(FILE* out, char* fn, struct module_env* env,
900238106Sdes	struct trust_anchor* tp)
901238106Sdes{
902238106Sdes	char tmi[32];
903238106Sdes	struct autr_ta* ta;
904238106Sdes	char* str;
905238106Sdes
906238106Sdes	/* write pretty header */
907238106Sdes	if(fprintf(out, "; autotrust trust anchor file\n") < 0) {
908238106Sdes		log_err("could not write to %s: %s", fn, strerror(errno));
909238106Sdes		return 0;
910238106Sdes	}
911238106Sdes	if(tp->autr->revoked) {
912238106Sdes		if(fprintf(out, ";;REVOKED\n") < 0 ||
913238106Sdes		   fprintf(out, "; The zone has all keys revoked, and is\n"
914238106Sdes			"; considered as if it has no trust anchors.\n"
915238106Sdes			"; the remainder of the file is the last probe.\n"
916238106Sdes			"; to restart the trust anchor, overwrite this file.\n"
917238106Sdes			"; with one containing valid DNSKEYs or DSes.\n") < 0) {
918238106Sdes		   log_err("could not write to %s: %s", fn, strerror(errno));
919238106Sdes		   return 0;
920238106Sdes		}
921238106Sdes	}
922238106Sdes	if(!print_id(out, fn, env, tp->name, tp->namelen, tp->dclass)) {
923238106Sdes		return 0;
924238106Sdes	}
925238106Sdes	if(fprintf(out, ";;last_queried: %u ;;%s",
926238106Sdes		(unsigned int)tp->autr->last_queried,
927238106Sdes		ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
928238106Sdes	   fprintf(out, ";;last_success: %u ;;%s",
929238106Sdes		(unsigned int)tp->autr->last_success,
930238106Sdes		ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
931238106Sdes	   fprintf(out, ";;next_probe_time: %u ;;%s",
932238106Sdes		(unsigned int)tp->autr->next_probe_time,
933238106Sdes		ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
934238106Sdes	   fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0
935238106Sdes	   || fprintf(out, ";;query_interval: %d\n",
936238106Sdes	   (int)tp->autr->query_interval) < 0 ||
937238106Sdes	   fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) {
938238106Sdes		log_err("could not write to %s: %s", fn, strerror(errno));
939238106Sdes		return 0;
940238106Sdes	}
941238106Sdes
942238106Sdes	/* write anchors */
943238106Sdes	for(ta=tp->autr->keys; ta; ta=ta->next) {
944238106Sdes		/* by default do not store START and REMOVED keys */
945238106Sdes		if(ta->s == AUTR_STATE_START)
946238106Sdes			continue;
947238106Sdes		if(ta->s == AUTR_STATE_REMOVED)
948238106Sdes			continue;
949238106Sdes		/* only store keys */
950238106Sdes		if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY)
951238106Sdes			continue;
952238106Sdes		str = ldns_rr2str(ta->rr);
953238106Sdes		if(!str || !str[0]) {
954238106Sdes			free(str);
955238106Sdes			log_err("malloc failure writing %s", fn);
956238106Sdes			return 0;
957238106Sdes		}
958238106Sdes		str[strlen(str)-1] = 0; /* remove newline */
959238106Sdes		if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d "
960238106Sdes			";;lastchange=%u ;;%s", str, (int)ta->s,
961238106Sdes			trustanchor_state2str(ta->s), (int)ta->pending_count,
962238106Sdes			(unsigned int)ta->last_change,
963238106Sdes			ctime_r(&(ta->last_change), tmi)) < 0) {
964238106Sdes		   log_err("could not write to %s: %s", fn, strerror(errno));
965238106Sdes		   free(str);
966238106Sdes		   return 0;
967238106Sdes		}
968238106Sdes		free(str);
969238106Sdes	}
970238106Sdes	return 1;
971238106Sdes}
972238106Sdes
973238106Sdesvoid autr_write_file(struct module_env* env, struct trust_anchor* tp)
974238106Sdes{
975238106Sdes	FILE* out;
976238106Sdes	char* fname = tp->autr->file;
977238106Sdes	char tempf[2048];
978238106Sdes	log_assert(tp->autr);
979238106Sdes	/* unique name with pid number and thread number */
980238106Sdes	snprintf(tempf, sizeof(tempf), "%s.%d-%d", fname, (int)getpid(),
981238106Sdes		env&&env->worker?*(int*)env->worker:0);
982238106Sdes	verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf);
983238106Sdes	out = fopen(tempf, "w");
984238106Sdes	if(!out) {
985238106Sdes		log_err("could not open autotrust file for writing, %s: %s",
986238106Sdes			tempf, strerror(errno));
987238106Sdes		return;
988238106Sdes	}
989238106Sdes	if(!autr_write_contents(out, tempf, env, tp)) {
990238106Sdes		/* failed to write contents (completely) */
991238106Sdes		fclose(out);
992238106Sdes		unlink(tempf);
993238106Sdes		log_err("could not completely write: %s", fname);
994238106Sdes		return;
995238106Sdes	}
996238106Sdes	/* success; overwrite actual file */
997238106Sdes	fclose(out);
998238106Sdes	verbose(VERB_ALGO, "autotrust: replaced %s", fname);
999238106Sdes#ifdef UB_ON_WINDOWS
1000238106Sdes	(void)unlink(fname); /* windows does not replace file with rename() */
1001238106Sdes#endif
1002238106Sdes	if(rename(tempf, fname) < 0) {
1003238106Sdes		log_err("rename(%s to %s): %s", tempf, fname, strerror(errno));
1004238106Sdes	}
1005238106Sdes}
1006238106Sdes
1007238106Sdes/**
1008238106Sdes * Verify if dnskey works for trust point
1009238106Sdes * @param env: environment (with time) for verification
1010238106Sdes * @param ve: validator environment (with options) for verification.
1011238106Sdes * @param tp: trust point to verify with
1012238106Sdes * @param rrset: DNSKEY rrset to verify.
1013238106Sdes * @return false on failure, true if verification successful.
1014238106Sdes */
1015238106Sdesstatic int
1016238106Sdesverify_dnskey(struct module_env* env, struct val_env* ve,
1017238106Sdes        struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
1018238106Sdes{
1019238106Sdes	char* reason = NULL;
1020238106Sdes	uint8_t sigalg[ALGO_NEEDS_MAX+1];
1021238106Sdes	int downprot = 1;
1022238106Sdes	enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
1023238106Sdes		tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
1024238106Sdes	/* sigalg is ignored, it returns algorithms signalled to exist, but
1025238106Sdes	 * in 5011 there are no other rrsets to check.  if downprot is
1026238106Sdes	 * enabled, then it checks that the DNSKEY is signed with all
1027238106Sdes	 * algorithms available in the trust store. */
1028238106Sdes	verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
1029238106Sdes		sec_status_to_string(sec));
1030238106Sdes	return sec == sec_status_secure;
1031238106Sdes}
1032238106Sdes
1033238106Sdes/** Find minimum expiration interval from signatures */
1034238106Sdesstatic uint32_t
1035238106Sdesmin_expiry(struct module_env* env, ldns_rr_list* rrset)
1036238106Sdes{
1037238106Sdes	size_t i;
1038238106Sdes	uint32_t t, r = 15 * 24 * 3600; /* 15 days max */
1039238106Sdes	for(i=0; i<ldns_rr_list_rr_count(rrset); i++) {
1040238106Sdes		ldns_rr* rr = ldns_rr_list_rr(rrset, i);
1041238106Sdes		if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG)
1042238106Sdes			continue;
1043238106Sdes		t = ldns_rdf2native_int32(ldns_rr_rrsig_expiration(rr));
1044238106Sdes		if(t - *env->now > 0) {
1045238106Sdes			t -= *env->now;
1046238106Sdes			if(t < r)
1047238106Sdes				r = t;
1048238106Sdes		}
1049238106Sdes	}
1050238106Sdes	return r;
1051238106Sdes}
1052238106Sdes
1053238106Sdes/** Is rr self-signed revoked key */
1054238106Sdesstatic int
1055238106Sdesrr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
1056238106Sdes	struct ub_packed_rrset_key* dnskey_rrset, size_t i)
1057238106Sdes{
1058238106Sdes	enum sec_status sec;
1059238106Sdes	char* reason = NULL;
1060238106Sdes	verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
1061238106Sdes		(int)i);
1062238106Sdes	/* no algorithm downgrade protection necessary, if it is selfsigned
1063238106Sdes	 * revoked it can be removed. */
1064238106Sdes	sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
1065238106Sdes		&reason);
1066238106Sdes	return (sec == sec_status_secure);
1067238106Sdes}
1068238106Sdes
1069238106Sdes/** Set fetched value */
1070238106Sdesstatic void
1071238106Sdesseen_trustanchor(struct autr_ta* ta, uint8_t seen)
1072238106Sdes{
1073238106Sdes	ta->fetched = seen;
1074238106Sdes	if(ta->pending_count < 250) /* no numerical overflow, please */
1075238106Sdes		ta->pending_count++;
1076238106Sdes}
1077238106Sdes
1078238106Sdes/** set revoked value */
1079238106Sdesstatic void
1080238106Sdesseen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked)
1081238106Sdes{
1082238106Sdes	ta->revoked = revoked;
1083238106Sdes}
1084238106Sdes
1085238106Sdes/** revoke a trust anchor */
1086238106Sdesstatic void
1087238106Sdesrevoke_dnskey(struct autr_ta* ta, int off)
1088238106Sdes{
1089238106Sdes        ldns_rdf* rdf;
1090238106Sdes        uint16_t flags;
1091238106Sdes	log_assert(ta && ta->rr);
1092238106Sdes	if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY)
1093238106Sdes		return;
1094238106Sdes	rdf = ldns_rr_dnskey_flags(ta->rr);
1095238106Sdes	flags = ldns_read_uint16(ldns_rdf_data(rdf));
1096238106Sdes
1097238106Sdes	if (off && (flags&LDNS_KEY_REVOKE_KEY))
1098238106Sdes		flags ^= LDNS_KEY_REVOKE_KEY; /* flip */
1099238106Sdes	else
1100238106Sdes		flags |= LDNS_KEY_REVOKE_KEY;
1101238106Sdes	ldns_write_uint16(ldns_rdf_data(rdf), flags);
1102238106Sdes}
1103238106Sdes
1104238106Sdes/** Compare two RR buffers skipping the REVOKED bit */
1105238106Sdesstatic int
1106238106Sdesldns_rr_compare_wire_skip_revbit(ldns_buffer* rr1_buf, ldns_buffer* rr2_buf)
1107238106Sdes{
1108238106Sdes	size_t rr1_len, rr2_len, min_len, i, offset;
1109238106Sdes	rr1_len = ldns_buffer_capacity(rr1_buf);
1110238106Sdes	rr2_len = ldns_buffer_capacity(rr2_buf);
1111238106Sdes	/* jump past dname (checked in earlier part) and especially past TTL */
1112238106Sdes	offset = 0;
1113238106Sdes	while (offset < rr1_len && *ldns_buffer_at(rr1_buf, offset) != 0)
1114238106Sdes		offset += *ldns_buffer_at(rr1_buf, offset) + 1;
1115238106Sdes	/* jump to rdata section (PAST the rdata length field) */
1116238106Sdes	offset += 11; /* 0-dname-end + type + class + ttl + rdatalen */
1117238106Sdes	min_len = (rr1_len < rr2_len) ? rr1_len : rr2_len;
1118238106Sdes	/* compare RRs RDATA byte for byte. */
1119238106Sdes	for(i = offset; i < min_len; i++)
1120238106Sdes	{
1121238106Sdes		uint8_t *rdf1, *rdf2;
1122238106Sdes		rdf1 = ldns_buffer_at(rr1_buf, i);
1123238106Sdes		rdf2 = ldns_buffer_at(rr2_buf, i);
1124238106Sdes		if (i==(offset+1))
1125238106Sdes		{
1126238106Sdes			/* this is the second part of the flags field */
1127238106Sdes			*rdf1 = *rdf1 | LDNS_KEY_REVOKE_KEY;
1128238106Sdes			*rdf2 = *rdf2 | LDNS_KEY_REVOKE_KEY;
1129238106Sdes		}
1130238106Sdes		if (*rdf1 < *rdf2)	return -1;
1131238106Sdes		else if (*rdf1 > *rdf2)	return 1;
1132238106Sdes        }
1133238106Sdes	return 0;
1134238106Sdes}
1135238106Sdes
1136238106Sdes/** Compare two RRs skipping the REVOKED bit */
1137238106Sdesstatic int
1138238106Sdesldns_rr_compare_skip_revbit(const ldns_rr* rr1, const ldns_rr* rr2, int* result)
1139238106Sdes{
1140238106Sdes	size_t rr1_len, rr2_len;
1141238106Sdes	ldns_buffer* rr1_buf;
1142238106Sdes	ldns_buffer* rr2_buf;
1143238106Sdes
1144238106Sdes	*result = ldns_rr_compare_no_rdata(rr1, rr2);
1145238106Sdes	if (*result == 0)
1146238106Sdes	{
1147238106Sdes		rr1_len = ldns_rr_uncompressed_size(rr1);
1148238106Sdes		rr2_len = ldns_rr_uncompressed_size(rr2);
1149238106Sdes		rr1_buf = ldns_buffer_new(rr1_len);
1150238106Sdes		rr2_buf = ldns_buffer_new(rr2_len);
1151238106Sdes		if(!rr1_buf || !rr2_buf) {
1152238106Sdes			ldns_buffer_free(rr1_buf);
1153238106Sdes			ldns_buffer_free(rr2_buf);
1154238106Sdes			return 0;
1155238106Sdes		}
1156238106Sdes		if (ldns_rr2buffer_wire_canonical(rr1_buf, rr1,
1157238106Sdes			LDNS_SECTION_ANY) != LDNS_STATUS_OK)
1158238106Sdes		{
1159238106Sdes			ldns_buffer_free(rr1_buf);
1160238106Sdes			ldns_buffer_free(rr2_buf);
1161238106Sdes			return 0;
1162238106Sdes		}
1163238106Sdes		if (ldns_rr2buffer_wire_canonical(rr2_buf, rr2,
1164238106Sdes			LDNS_SECTION_ANY) != LDNS_STATUS_OK) {
1165238106Sdes			ldns_buffer_free(rr1_buf);
1166238106Sdes			ldns_buffer_free(rr2_buf);
1167238106Sdes			return 0;
1168238106Sdes		}
1169238106Sdes		*result = ldns_rr_compare_wire_skip_revbit(rr1_buf, rr2_buf);
1170238106Sdes		ldns_buffer_free(rr1_buf);
1171238106Sdes		ldns_buffer_free(rr2_buf);
1172238106Sdes	}
1173238106Sdes	return 1;
1174238106Sdes}
1175238106Sdes
1176238106Sdes
1177238106Sdes/** compare two trust anchors */
1178238106Sdesstatic int
1179238106Sdesta_compare(ldns_rr* a, ldns_rr* b, int* result)
1180238106Sdes{
1181238106Sdes	if (!a && !b)	*result = 0;
1182238106Sdes	else if (!a)	*result = -1;
1183238106Sdes	else if (!b)	*result = 1;
1184238106Sdes	else if (ldns_rr_get_type(a) != ldns_rr_get_type(b))
1185238106Sdes		*result = (int)ldns_rr_get_type(a) - (int)ldns_rr_get_type(b);
1186238106Sdes	else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DNSKEY) {
1187238106Sdes		if(!ldns_rr_compare_skip_revbit(a, b, result))
1188238106Sdes			return 0;
1189238106Sdes	}
1190238106Sdes	else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DS)
1191238106Sdes		*result = ldns_rr_compare(a, b);
1192238106Sdes	else    *result = -1;
1193238106Sdes	return 1;
1194238106Sdes}
1195238106Sdes
1196238106Sdes/**
1197238106Sdes * Find key
1198238106Sdes * @param tp: to search in
1199238106Sdes * @param rr: to look for
1200238106Sdes * @param result: returns NULL or the ta key looked for.
1201238106Sdes * @return false on malloc failure during search. if true examine result.
1202238106Sdes */
1203238106Sdesstatic int
1204238106Sdesfind_key(struct trust_anchor* tp, ldns_rr* rr, struct autr_ta** result)
1205238106Sdes{
1206238106Sdes	struct autr_ta* ta;
1207238106Sdes	int ret;
1208238106Sdes	if(!tp || !rr)
1209238106Sdes		return 0;
1210238106Sdes	for(ta=tp->autr->keys; ta; ta=ta->next) {
1211238106Sdes		if(!ta_compare(ta->rr, rr, &ret))
1212238106Sdes			return 0;
1213238106Sdes		if(ret == 0) {
1214238106Sdes			*result = ta;
1215238106Sdes			return 1;
1216238106Sdes		}
1217238106Sdes	}
1218238106Sdes	*result = NULL;
1219238106Sdes	return 1;
1220238106Sdes}
1221238106Sdes
1222238106Sdes/** add key and clone RR and tp already locked */
1223238106Sdesstatic struct autr_ta*
1224238106Sdesadd_key(struct trust_anchor* tp, ldns_rr* rr)
1225238106Sdes{
1226238106Sdes	ldns_rr* c;
1227238106Sdes	struct autr_ta* ta;
1228238106Sdes	c = ldns_rr_clone(rr);
1229238106Sdes	if(!c) return NULL;
1230238106Sdes	ta = autr_ta_create(c);
1231238106Sdes	if(!ta) {
1232238106Sdes		ldns_rr_free(c);
1233238106Sdes		return NULL;
1234238106Sdes	}
1235238106Sdes	/* link in, tp already locked */
1236238106Sdes	ta->next = tp->autr->keys;
1237238106Sdes	tp->autr->keys = ta;
1238238106Sdes	return ta;
1239238106Sdes}
1240238106Sdes
1241238106Sdes/** get TTL from DNSKEY rrset */
1242238106Sdesstatic uint32_t
1243238106Sdeskey_ttl(struct ub_packed_rrset_key* k)
1244238106Sdes{
1245238106Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
1246238106Sdes	return d->ttl;
1247238106Sdes}
1248238106Sdes
1249238106Sdes/** update the time values for the trustpoint */
1250238106Sdesstatic void
1251238106Sdesset_tp_times(struct trust_anchor* tp, uint32_t rrsig_exp_interval,
1252238106Sdes	uint32_t origttl, int* changed)
1253238106Sdes{
1254238106Sdes	uint32_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time;
1255238106Sdes
1256238106Sdes	/* x = MIN(15days, ttl/2, expire/2) */
1257238106Sdes	x = 15 * 24 * 3600;
1258238106Sdes	if(origttl/2 < x)
1259238106Sdes		x = origttl/2;
1260238106Sdes	if(rrsig_exp_interval/2 < x)
1261238106Sdes		x = rrsig_exp_interval/2;
1262238106Sdes	/* MAX(1hr, x) */
1263238106Sdes	if(x < 3600)
1264238106Sdes		tp->autr->query_interval = 3600;
1265238106Sdes	else	tp->autr->query_interval = x;
1266238106Sdes
1267238106Sdes	/* x= MIN(1day, ttl/10, expire/10) */
1268238106Sdes	x = 24 * 3600;
1269238106Sdes	if(origttl/10 < x)
1270238106Sdes		x = origttl/10;
1271238106Sdes	if(rrsig_exp_interval/10 < x)
1272238106Sdes		x = rrsig_exp_interval/10;
1273238106Sdes	/* MAX(1hr, x) */
1274238106Sdes	if(x < 3600)
1275238106Sdes		tp->autr->retry_time = 3600;
1276238106Sdes	else	tp->autr->retry_time = x;
1277238106Sdes
1278238106Sdes	if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) {
1279238106Sdes		*changed = 1;
1280238106Sdes		verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl);
1281238106Sdes		verbose(VERB_ALGO, "rrsig_exp_interval is %d",
1282238106Sdes			(int)rrsig_exp_interval);
1283238106Sdes		verbose(VERB_ALGO, "query_interval: %d, retry_time: %d",
1284238106Sdes			(int)tp->autr->query_interval,
1285238106Sdes			(int)tp->autr->retry_time);
1286238106Sdes	}
1287238106Sdes}
1288238106Sdes
1289238106Sdes/** init events to zero */
1290238106Sdesstatic void
1291238106Sdesinit_events(struct trust_anchor* tp)
1292238106Sdes{
1293238106Sdes	struct autr_ta* ta;
1294238106Sdes	for(ta=tp->autr->keys; ta; ta=ta->next) {
1295238106Sdes		ta->fetched = 0;
1296238106Sdes	}
1297238106Sdes}
1298238106Sdes
1299238106Sdes/** check for revoked keys without trusting any other information */
1300238106Sdesstatic void
1301238106Sdescheck_contains_revoked(struct module_env* env, struct val_env* ve,
1302238106Sdes	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
1303238106Sdes	int* changed)
1304238106Sdes{
1305238106Sdes	ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset,
1306238106Sdes		env->scratch_buffer);
1307238106Sdes	size_t i;
1308238106Sdes	if(!r) {
1309238106Sdes		log_err("malloc failure");
1310238106Sdes		return;
1311238106Sdes	}
1312238106Sdes	for(i=0; i<ldns_rr_list_rr_count(r); i++) {
1313238106Sdes		ldns_rr* rr = ldns_rr_list_rr(r, i);
1314238106Sdes		struct autr_ta* ta = NULL;
1315238106Sdes		if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)
1316238106Sdes			continue;
1317238106Sdes		if(!rr_is_dnskey_sep(rr) || !rr_is_dnskey_revoked(rr))
1318238106Sdes			continue; /* not a revoked KSK */
1319238106Sdes		if(!find_key(tp, rr, &ta)) {
1320238106Sdes			log_err("malloc failure");
1321238106Sdes			continue; /* malloc fail in compare*/
1322238106Sdes		}
1323238106Sdes		if(!ta)
1324238106Sdes			continue; /* key not found */
1325238106Sdes		if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) {
1326238106Sdes			/* checked if there is an rrsig signed by this key. */
1327238106Sdes			log_assert(dnskey_calc_keytag(dnskey_rrset, i) ==
1328238106Sdes				ldns_calc_keytag(rr)); /* checks conversion*/
1329238106Sdes			verbose_key(ta, VERB_ALGO, "is self-signed revoked");
1330238106Sdes			if(!ta->revoked)
1331238106Sdes				*changed = 1;
1332238106Sdes			seen_revoked_trustanchor(ta, 1);
1333238106Sdes			do_revoked(env, ta, changed);
1334238106Sdes		}
1335238106Sdes	}
1336238106Sdes	ldns_rr_list_deep_free(r);
1337238106Sdes}
1338238106Sdes
1339238106Sdes/** See if a DNSKEY is verified by one of the DSes */
1340238106Sdesstatic int
1341238106Sdeskey_matches_a_ds(struct module_env* env, struct val_env* ve,
1342238106Sdes	struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx,
1343238106Sdes	struct ub_packed_rrset_key* ds_rrset)
1344238106Sdes{
1345238106Sdes	struct packed_rrset_data* dd = (struct packed_rrset_data*)
1346238106Sdes	                ds_rrset->entry.data;
1347238106Sdes	size_t ds_idx, num = dd->count;
1348238106Sdes	int d = val_favorite_ds_algo(ds_rrset);
1349238106Sdes	char* reason = "";
1350238106Sdes	for(ds_idx=0; ds_idx<num; ds_idx++) {
1351238106Sdes		if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) ||
1352238106Sdes			!ds_key_algo_is_supported(ds_rrset, ds_idx) ||
1353238106Sdes			ds_get_digest_algo(ds_rrset, ds_idx) != d)
1354238106Sdes			continue;
1355238106Sdes		if(ds_get_key_algo(ds_rrset, ds_idx)
1356238106Sdes		   != dnskey_get_algo(dnskey_rrset, key_idx)
1357238106Sdes		   || dnskey_calc_keytag(dnskey_rrset, key_idx)
1358238106Sdes		   != ds_get_keytag(ds_rrset, ds_idx)) {
1359238106Sdes			continue;
1360238106Sdes		}
1361238106Sdes		if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx,
1362238106Sdes			ds_rrset, ds_idx)) {
1363238106Sdes			verbose(VERB_ALGO, "DS match attempt failed");
1364238106Sdes			continue;
1365238106Sdes		}
1366238106Sdes		if(dnskey_verify_rrset(env, ve, dnskey_rrset,
1367238106Sdes			dnskey_rrset, key_idx, &reason) == sec_status_secure) {
1368238106Sdes			return 1;
1369238106Sdes		} else {
1370238106Sdes			verbose(VERB_ALGO, "DS match failed because the key "
1371238106Sdes				"does not verify the keyset: %s", reason);
1372238106Sdes		}
1373238106Sdes	}
1374238106Sdes	return 0;
1375238106Sdes}
1376238106Sdes
1377238106Sdes/** Set update events */
1378238106Sdesstatic int
1379238106Sdesupdate_events(struct module_env* env, struct val_env* ve,
1380238106Sdes	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
1381238106Sdes	int* changed)
1382238106Sdes{
1383238106Sdes	ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset,
1384238106Sdes		env->scratch_buffer);
1385238106Sdes	size_t i;
1386238106Sdes	if(!r)
1387238106Sdes		return 0;
1388238106Sdes	init_events(tp);
1389238106Sdes	for(i=0; i<ldns_rr_list_rr_count(r); i++) {
1390238106Sdes		ldns_rr* rr = ldns_rr_list_rr(r, i);
1391238106Sdes		struct autr_ta* ta = NULL;
1392238106Sdes		if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)
1393238106Sdes			continue;
1394238106Sdes		if(!rr_is_dnskey_sep(rr))
1395238106Sdes			continue;
1396238106Sdes		if(rr_is_dnskey_revoked(rr)) {
1397238106Sdes			/* self-signed revoked keys already detected before,
1398238106Sdes			 * other revoked keys are not 'added' again */
1399238106Sdes			continue;
1400238106Sdes		}
1401238106Sdes		/* is a key of this type supported?. Note rr_list and
1402238106Sdes		 * packed_rrset are in the same order. */
1403238106Sdes		if(!dnskey_algo_is_supported(dnskey_rrset, i)) {
1404238106Sdes			/* skip unknown algorithm key, it is useless to us */
1405238106Sdes			log_nametypeclass(VERB_DETAIL, "trust point has "
1406238106Sdes				"unsupported algorithm at",
1407238106Sdes				tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
1408238106Sdes			continue;
1409238106Sdes		}
1410238106Sdes
1411238106Sdes		/* is it new? if revocation bit set, find the unrevoked key */
1412238106Sdes		if(!find_key(tp, rr, &ta)) {
1413238106Sdes			ldns_rr_list_deep_free(r); /* malloc fail in compare*/
1414238106Sdes			return 0;
1415238106Sdes		}
1416238106Sdes		if(!ta) {
1417238106Sdes			ta = add_key(tp, rr);
1418238106Sdes			*changed = 1;
1419238106Sdes			/* first time seen, do we have DSes? if match: VALID */
1420238106Sdes			if(ta && tp->ds_rrset && key_matches_a_ds(env, ve,
1421238106Sdes				dnskey_rrset, i, tp->ds_rrset)) {
1422238106Sdes				verbose_key(ta, VERB_ALGO, "verified by DS");
1423238106Sdes				ta->s = AUTR_STATE_VALID;
1424238106Sdes			}
1425238106Sdes		}
1426238106Sdes		if(!ta) {
1427238106Sdes			ldns_rr_list_deep_free(r);
1428238106Sdes			return 0;
1429238106Sdes		}
1430238106Sdes		seen_trustanchor(ta, 1);
1431238106Sdes		verbose_key(ta, VERB_ALGO, "in DNS response");
1432238106Sdes	}
1433238106Sdes	set_tp_times(tp, min_expiry(env, r), key_ttl(dnskey_rrset), changed);
1434238106Sdes	ldns_rr_list_deep_free(r);
1435238106Sdes	return 1;
1436238106Sdes}
1437238106Sdes
1438238106Sdes/**
1439238106Sdes * Check if the holddown time has already exceeded
1440238106Sdes * setting: add-holddown: add holddown timer
1441238106Sdes * setting: del-holddown: del holddown timer
1442238106Sdes * @param env: environment with current time
1443238106Sdes * @param ta: trust anchor to check for.
1444238106Sdes * @param holddown: the timer value
1445238106Sdes * @return number of seconds the holddown has passed.
1446238106Sdes */
1447238106Sdesstatic int
1448238106Sdescheck_holddown(struct module_env* env, struct autr_ta* ta,
1449238106Sdes	unsigned int holddown)
1450238106Sdes{
1451238106Sdes        unsigned int elapsed;
1452238106Sdes	if((unsigned)*env->now < (unsigned)ta->last_change) {
1453238106Sdes		log_warn("time goes backwards. delaying key holddown");
1454238106Sdes		return 0;
1455238106Sdes	}
1456238106Sdes	elapsed = (unsigned)*env->now - (unsigned)ta->last_change;
1457238106Sdes        if (elapsed > holddown) {
1458238106Sdes                return (int) (elapsed-holddown);
1459238106Sdes        }
1460238106Sdes	verbose_key(ta, VERB_ALGO, "holddown time %d seconds to go",
1461238106Sdes		(int) (holddown-elapsed));
1462238106Sdes        return 0;
1463238106Sdes}
1464238106Sdes
1465238106Sdes
1466238106Sdes/** Set last_change to now */
1467238106Sdesstatic void
1468238106Sdesreset_holddown(struct module_env* env, struct autr_ta* ta, int* changed)
1469238106Sdes{
1470238106Sdes	ta->last_change = *env->now;
1471238106Sdes	*changed = 1;
1472238106Sdes}
1473238106Sdes
1474238106Sdes/** Set the state for this trust anchor */
1475238106Sdesstatic void
1476238106Sdesset_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed,
1477238106Sdes	autr_state_t s)
1478238106Sdes{
1479238106Sdes	verbose_key(ta, VERB_ALGO, "update: %s to %s",
1480238106Sdes		trustanchor_state2str(ta->s), trustanchor_state2str(s));
1481238106Sdes	ta->s = s;
1482238106Sdes	reset_holddown(env, ta, changed);
1483238106Sdes}
1484238106Sdes
1485238106Sdes
1486238106Sdes/** Event: NewKey */
1487238106Sdesstatic void
1488238106Sdesdo_newkey(struct module_env* env, struct autr_ta* anchor, int* c)
1489238106Sdes{
1490238106Sdes	if (anchor->s == AUTR_STATE_START)
1491238106Sdes		set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND);
1492238106Sdes}
1493238106Sdes
1494238106Sdes/** Event: AddTime */
1495238106Sdesstatic void
1496238106Sdesdo_addtime(struct module_env* env, struct autr_ta* anchor, int* c)
1497238106Sdes{
1498238106Sdes	/* This not according to RFC, this is 30 days, but the RFC demands
1499238106Sdes	 * MAX(30days, TTL expire time of first DNSKEY set with this key),
1500238106Sdes	 * The value may be too small if a very large TTL was used. */
1501238106Sdes	int exceeded = check_holddown(env, anchor, env->cfg->add_holddown);
1502238106Sdes	if (exceeded && anchor->s == AUTR_STATE_ADDPEND) {
1503238106Sdes		verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded "
1504238106Sdes			"%d seconds ago, and pending-count %d", exceeded,
1505238106Sdes			anchor->pending_count);
1506238106Sdes		if(anchor->pending_count >= MIN_PENDINGCOUNT) {
1507238106Sdes			set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
1508238106Sdes			anchor->pending_count = 0;
1509238106Sdes			return;
1510238106Sdes		}
1511238106Sdes		verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check "
1512238106Sdes			"failed (pending count: %d)", anchor->pending_count);
1513238106Sdes	}
1514238106Sdes}
1515238106Sdes
1516238106Sdes/** Event: RemTime */
1517238106Sdesstatic void
1518238106Sdesdo_remtime(struct module_env* env, struct autr_ta* anchor, int* c)
1519238106Sdes{
1520238106Sdes	int exceeded = check_holddown(env, anchor, env->cfg->del_holddown);
1521238106Sdes	if(exceeded && anchor->s == AUTR_STATE_REVOKED) {
1522238106Sdes		verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded "
1523238106Sdes			"%d seconds ago", exceeded);
1524238106Sdes		set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED);
1525238106Sdes	}
1526238106Sdes}
1527238106Sdes
1528238106Sdes/** Event: KeyRem */
1529238106Sdesstatic void
1530238106Sdesdo_keyrem(struct module_env* env, struct autr_ta* anchor, int* c)
1531238106Sdes{
1532238106Sdes	if(anchor->s == AUTR_STATE_ADDPEND) {
1533238106Sdes		set_trustanchor_state(env, anchor, c, AUTR_STATE_START);
1534238106Sdes		anchor->pending_count = 0;
1535238106Sdes	} else if(anchor->s == AUTR_STATE_VALID)
1536238106Sdes		set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING);
1537238106Sdes}
1538238106Sdes
1539238106Sdes/** Event: KeyPres */
1540238106Sdesstatic void
1541238106Sdesdo_keypres(struct module_env* env, struct autr_ta* anchor, int* c)
1542238106Sdes{
1543238106Sdes	if(anchor->s == AUTR_STATE_MISSING)
1544238106Sdes		set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
1545238106Sdes}
1546238106Sdes
1547238106Sdes/* Event: Revoked */
1548238106Sdesstatic void
1549238106Sdesdo_revoked(struct module_env* env, struct autr_ta* anchor, int* c)
1550238106Sdes{
1551238106Sdes	if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) {
1552238106Sdes                set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED);
1553238106Sdes		verbose_key(anchor, VERB_ALGO, "old id, prior to revocation");
1554238106Sdes                revoke_dnskey(anchor, 0);
1555238106Sdes		verbose_key(anchor, VERB_ALGO, "new id, after revocation");
1556238106Sdes	}
1557238106Sdes}
1558238106Sdes
1559238106Sdes/** Do statestable transition matrix for anchor */
1560238106Sdesstatic void
1561238106Sdesanchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c)
1562238106Sdes{
1563238106Sdes	log_assert(anchor);
1564238106Sdes	switch(anchor->s) {
1565238106Sdes	/* START */
1566238106Sdes	case AUTR_STATE_START:
1567238106Sdes		/* NewKey: ADDPEND */
1568238106Sdes		if (anchor->fetched)
1569238106Sdes			do_newkey(env, anchor, c);
1570238106Sdes		break;
1571238106Sdes	/* ADDPEND */
1572238106Sdes	case AUTR_STATE_ADDPEND:
1573238106Sdes		/* KeyRem: START */
1574238106Sdes		if (!anchor->fetched)
1575238106Sdes			do_keyrem(env, anchor, c);
1576238106Sdes		/* AddTime: VALID */
1577238106Sdes		else	do_addtime(env, anchor, c);
1578238106Sdes		break;
1579238106Sdes	/* VALID */
1580238106Sdes	case AUTR_STATE_VALID:
1581238106Sdes		/* RevBit: REVOKED */
1582238106Sdes		if (anchor->revoked)
1583238106Sdes			do_revoked(env, anchor, c);
1584238106Sdes		/* KeyRem: MISSING */
1585238106Sdes		else if (!anchor->fetched)
1586238106Sdes			do_keyrem(env, anchor, c);
1587238106Sdes		else if(!anchor->last_change) {
1588238106Sdes			verbose_key(anchor, VERB_ALGO, "first seen");
1589238106Sdes			reset_holddown(env, anchor, c);
1590238106Sdes		}
1591238106Sdes		break;
1592238106Sdes	/* MISSING */
1593238106Sdes	case AUTR_STATE_MISSING:
1594238106Sdes		/* RevBit: REVOKED */
1595238106Sdes		if (anchor->revoked)
1596238106Sdes			do_revoked(env, anchor, c);
1597238106Sdes		/* KeyPres */
1598238106Sdes		else if (anchor->fetched)
1599238106Sdes			do_keypres(env, anchor, c);
1600238106Sdes		break;
1601238106Sdes	/* REVOKED */
1602238106Sdes	case AUTR_STATE_REVOKED:
1603238106Sdes		if (anchor->fetched)
1604238106Sdes			reset_holddown(env, anchor, c);
1605238106Sdes		/* RemTime: REMOVED */
1606238106Sdes		else	do_remtime(env, anchor, c);
1607238106Sdes		break;
1608238106Sdes	/* REMOVED */
1609238106Sdes	case AUTR_STATE_REMOVED:
1610238106Sdes	default:
1611238106Sdes		break;
1612238106Sdes	}
1613238106Sdes}
1614238106Sdes
1615238106Sdes/** if ZSK init then trust KSKs */
1616238106Sdesstatic int
1617238106Sdesinit_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed)
1618238106Sdes{
1619238106Sdes	/* search for VALID ZSKs */
1620238106Sdes	struct autr_ta* anchor;
1621238106Sdes	int validzsk = 0;
1622238106Sdes	int validksk = 0;
1623238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1624238106Sdes		/* last_change test makes sure it was manually configured */
1625238106Sdes                if (ldns_rr_get_type(anchor->rr) == LDNS_RR_TYPE_DNSKEY &&
1626238106Sdes			anchor->last_change == 0 &&
1627238106Sdes			!rr_is_dnskey_sep(anchor->rr) &&
1628238106Sdes			anchor->s == AUTR_STATE_VALID)
1629238106Sdes                        validzsk++;
1630238106Sdes	}
1631238106Sdes	if(validzsk == 0)
1632238106Sdes		return 0;
1633238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1634238106Sdes                if (rr_is_dnskey_sep(anchor->rr) &&
1635238106Sdes			anchor->s == AUTR_STATE_ADDPEND) {
1636238106Sdes			verbose_key(anchor, VERB_ALGO, "trust KSK from "
1637238106Sdes				"ZSK(config)");
1638238106Sdes			set_trustanchor_state(env, anchor, changed,
1639238106Sdes				AUTR_STATE_VALID);
1640238106Sdes			validksk++;
1641238106Sdes		}
1642238106Sdes	}
1643238106Sdes	return validksk;
1644238106Sdes}
1645238106Sdes
1646238106Sdes/** Remove missing trustanchors so the list does not grow forever */
1647238106Sdesstatic void
1648238106Sdesremove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp,
1649238106Sdes	int* changed)
1650238106Sdes{
1651238106Sdes	struct autr_ta* anchor;
1652238106Sdes	int exceeded;
1653238106Sdes	int valid = 0;
1654238106Sdes	/* see if we have anchors that are valid */
1655238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1656238106Sdes		/* Only do KSKs */
1657238106Sdes                if (!rr_is_dnskey_sep(anchor->rr))
1658238106Sdes                        continue;
1659238106Sdes                if (anchor->s == AUTR_STATE_VALID)
1660238106Sdes                        valid++;
1661238106Sdes	}
1662238106Sdes	/* if there are no SEP Valid anchors, see if we started out with
1663238106Sdes	 * a ZSK (last-change=0) anchor, which is VALID and there are KSKs
1664238106Sdes	 * now that can be made valid.  Do this immediately because there
1665238106Sdes	 * is no guarantee that the ZSKs get announced long enough.  Usually
1666238106Sdes	 * this is immediately after init with a ZSK trusted, unless the domain
1667238106Sdes	 * was not advertising any KSKs at all.  In which case we perfectly
1668238106Sdes	 * track the zero number of KSKs. */
1669238106Sdes	if(valid == 0) {
1670238106Sdes		valid = init_zsk_to_ksk(env, tp, changed);
1671238106Sdes		if(valid == 0)
1672238106Sdes			return;
1673238106Sdes	}
1674238106Sdes
1675238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1676238106Sdes		/* ignore ZSKs if newly added */
1677238106Sdes		if(anchor->s == AUTR_STATE_START)
1678238106Sdes			continue;
1679238106Sdes		/* remove ZSKs if a KSK is present */
1680238106Sdes                if (!rr_is_dnskey_sep(anchor->rr)) {
1681238106Sdes			if(valid > 0) {
1682238106Sdes				verbose_key(anchor, VERB_ALGO, "remove ZSK "
1683238106Sdes					"[%d key(s) VALID]", valid);
1684238106Sdes				set_trustanchor_state(env, anchor, changed,
1685238106Sdes					AUTR_STATE_REMOVED);
1686238106Sdes			}
1687238106Sdes                        continue;
1688238106Sdes		}
1689238106Sdes                /* Only do MISSING keys */
1690238106Sdes                if (anchor->s != AUTR_STATE_MISSING)
1691238106Sdes                        continue;
1692238106Sdes		if(env->cfg->keep_missing == 0)
1693238106Sdes			continue; /* keep forever */
1694238106Sdes
1695238106Sdes		exceeded = check_holddown(env, anchor, env->cfg->keep_missing);
1696238106Sdes		/* If keep_missing has exceeded and we still have more than
1697238106Sdes		 * one valid KSK: remove missing trust anchor */
1698238106Sdes                if (exceeded && valid > 0) {
1699238106Sdes			verbose_key(anchor, VERB_ALGO, "keep-missing time "
1700238106Sdes				"exceeded %d seconds ago, [%d key(s) VALID]",
1701238106Sdes				exceeded, valid);
1702238106Sdes			set_trustanchor_state(env, anchor, changed,
1703238106Sdes				AUTR_STATE_REMOVED);
1704238106Sdes		}
1705238106Sdes	}
1706238106Sdes}
1707238106Sdes
1708238106Sdes/** Do the statetable from RFC5011 transition matrix */
1709238106Sdesstatic int
1710238106Sdesdo_statetable(struct module_env* env, struct trust_anchor* tp, int* changed)
1711238106Sdes{
1712238106Sdes	struct autr_ta* anchor;
1713238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1714238106Sdes		/* Only do KSKs */
1715238106Sdes		if(!rr_is_dnskey_sep(anchor->rr))
1716238106Sdes			continue;
1717238106Sdes		anchor_state_update(env, anchor, changed);
1718238106Sdes	}
1719238106Sdes	remove_missing_trustanchors(env, tp, changed);
1720238106Sdes	return 1;
1721238106Sdes}
1722238106Sdes
1723238106Sdes/** See if time alone makes ADDPEND to VALID transition */
1724238106Sdesstatic void
1725238106Sdesautr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c)
1726238106Sdes{
1727238106Sdes	struct autr_ta* anchor;
1728238106Sdes	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
1729238106Sdes		if(rr_is_dnskey_sep(anchor->rr) &&
1730238106Sdes			anchor->s == AUTR_STATE_ADDPEND)
1731238106Sdes			do_addtime(env, anchor, c);
1732238106Sdes	}
1733238106Sdes}
1734238106Sdes
1735238106Sdes/** cleanup key list */
1736238106Sdesstatic void
1737238106Sdesautr_cleanup_keys(struct trust_anchor* tp)
1738238106Sdes{
1739238106Sdes	struct autr_ta* p, **prevp;
1740238106Sdes	prevp = &tp->autr->keys;
1741238106Sdes	p = tp->autr->keys;
1742238106Sdes	while(p) {
1743238106Sdes		/* do we want to remove this key? */
1744238106Sdes		if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED ||
1745238106Sdes			ldns_rr_get_type(p->rr) != LDNS_RR_TYPE_DNSKEY) {
1746238106Sdes			struct autr_ta* np = p->next;
1747238106Sdes			/* remove */
1748238106Sdes			ldns_rr_free(p->rr);
1749238106Sdes			free(p);
1750238106Sdes			/* snip and go to next item */
1751238106Sdes			*prevp = np;
1752238106Sdes			p = np;
1753238106Sdes			continue;
1754238106Sdes		}
1755238106Sdes		/* remove pending counts if no longer pending */
1756238106Sdes		if(p->s != AUTR_STATE_ADDPEND)
1757238106Sdes			p->pending_count = 0;
1758238106Sdes		prevp = &p->next;
1759238106Sdes		p = p->next;
1760238106Sdes	}
1761238106Sdes}
1762238106Sdes
1763238106Sdes/** calculate next probe time */
1764238106Sdesstatic time_t
1765238106Sdescalc_next_probe(struct module_env* env, uint32_t wait)
1766238106Sdes{
1767238106Sdes	/* make it random, 90-100% */
1768238106Sdes	uint32_t rnd, rest;
1769238106Sdes	if(wait < 3600)
1770238106Sdes		wait = 3600;
1771238106Sdes	rnd = wait/10;
1772238106Sdes	rest = wait-rnd;
1773238106Sdes	rnd = (uint32_t)ub_random_max(env->rnd, (long int)rnd);
1774238106Sdes	return (time_t)(*env->now + rest + rnd);
1775238106Sdes}
1776238106Sdes
1777238106Sdes/** what is first probe time (anchors must be locked) */
1778238106Sdesstatic time_t
1779238106Sdeswait_probe_time(struct val_anchors* anchors)
1780238106Sdes{
1781238106Sdes	rbnode_t* t = rbtree_first(&anchors->autr->probe);
1782238106Sdes	if(t != RBTREE_NULL)
1783238106Sdes		return ((struct trust_anchor*)t->key)->autr->next_probe_time;
1784238106Sdes	return 0;
1785238106Sdes}
1786238106Sdes
1787238106Sdes/** reset worker timer */
1788238106Sdesstatic void
1789238106Sdesreset_worker_timer(struct module_env* env)
1790238106Sdes{
1791238106Sdes	struct timeval tv;
1792238106Sdes#ifndef S_SPLINT_S
1793238106Sdes	uint32_t next = (uint32_t)wait_probe_time(env->anchors);
1794238106Sdes	/* in case this is libunbound, no timer */
1795238106Sdes	if(!env->probe_timer)
1796238106Sdes		return;
1797238106Sdes	if(next > *env->now)
1798238106Sdes		tv.tv_sec = (time_t)(next - *env->now);
1799238106Sdes	else	tv.tv_sec = 0;
1800238106Sdes#endif
1801238106Sdes	tv.tv_usec = 0;
1802238106Sdes	comm_timer_set(env->probe_timer, &tv);
1803238106Sdes	verbose(VERB_ALGO, "scheduled next probe in %d sec", (int)tv.tv_sec);
1804238106Sdes}
1805238106Sdes
1806238106Sdes/** set next probe for trust anchor */
1807238106Sdesstatic int
1808238106Sdesset_next_probe(struct module_env* env, struct trust_anchor* tp,
1809238106Sdes	struct ub_packed_rrset_key* dnskey_rrset)
1810238106Sdes{
1811238106Sdes	struct trust_anchor key, *tp2;
1812238106Sdes	time_t mold, mnew;
1813238106Sdes	/* use memory allocated in rrset for temporary name storage */
1814238106Sdes	key.node.key = &key;
1815238106Sdes	key.name = dnskey_rrset->rk.dname;
1816238106Sdes	key.namelen = dnskey_rrset->rk.dname_len;
1817238106Sdes	key.namelabs = dname_count_labels(key.name);
1818238106Sdes	key.dclass = tp->dclass;
1819238106Sdes	lock_basic_unlock(&tp->lock);
1820238106Sdes
1821238106Sdes	/* fetch tp again and lock anchors, so that we can modify the trees */
1822238106Sdes	lock_basic_lock(&env->anchors->lock);
1823238106Sdes	tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key);
1824238106Sdes	if(!tp2) {
1825238106Sdes		verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe");
1826238106Sdes		lock_basic_unlock(&env->anchors->lock);
1827238106Sdes		return 0;
1828238106Sdes	}
1829238106Sdes	log_assert(tp == tp2);
1830238106Sdes	lock_basic_lock(&tp->lock);
1831238106Sdes
1832238106Sdes	/* schedule */
1833238106Sdes	mold = wait_probe_time(env->anchors);
1834238106Sdes	(void)rbtree_delete(&env->anchors->autr->probe, tp);
1835238106Sdes	tp->autr->next_probe_time = calc_next_probe(env,
1836238106Sdes		tp->autr->query_interval);
1837238106Sdes	(void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
1838238106Sdes	mnew = wait_probe_time(env->anchors);
1839238106Sdes
1840238106Sdes	lock_basic_unlock(&env->anchors->lock);
1841238106Sdes	verbose(VERB_ALGO, "next probe set in %d seconds",
1842238106Sdes		(int)tp->autr->next_probe_time - (int)*env->now);
1843238106Sdes	if(mold != mnew) {
1844238106Sdes		reset_worker_timer(env);
1845238106Sdes	}
1846238106Sdes	return 1;
1847238106Sdes}
1848238106Sdes
1849238106Sdes/** Revoke and Delete a trust point */
1850238106Sdesstatic void
1851238106Sdesautr_tp_remove(struct module_env* env, struct trust_anchor* tp,
1852238106Sdes	struct ub_packed_rrset_key* dnskey_rrset)
1853238106Sdes{
1854249141Sdes	struct trust_anchor* del_tp;
1855238106Sdes	struct trust_anchor key;
1856238106Sdes	struct autr_point_data pd;
1857238106Sdes	time_t mold, mnew;
1858238106Sdes
1859238106Sdes	log_nametypeclass(VERB_OPS, "trust point was revoked",
1860238106Sdes		tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
1861238106Sdes	tp->autr->revoked = 1;
1862238106Sdes
1863238106Sdes	/* use space allocated for dnskey_rrset to save name of anchor */
1864238106Sdes	memset(&key, 0, sizeof(key));
1865238106Sdes	memset(&pd, 0, sizeof(pd));
1866238106Sdes	key.autr = &pd;
1867238106Sdes	key.node.key = &key;
1868238106Sdes	pd.pnode.key = &key;
1869238106Sdes	pd.next_probe_time = tp->autr->next_probe_time;
1870238106Sdes	key.name = dnskey_rrset->rk.dname;
1871238106Sdes	key.namelen = tp->namelen;
1872238106Sdes	key.namelabs = tp->namelabs;
1873238106Sdes	key.dclass = tp->dclass;
1874238106Sdes
1875238106Sdes	/* unlock */
1876238106Sdes	lock_basic_unlock(&tp->lock);
1877238106Sdes
1878238106Sdes	/* take from tree. It could be deleted by someone else,hence (void). */
1879238106Sdes	lock_basic_lock(&env->anchors->lock);
1880249141Sdes	del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key);
1881238106Sdes	mold = wait_probe_time(env->anchors);
1882238106Sdes	(void)rbtree_delete(&env->anchors->autr->probe, &key);
1883238106Sdes	mnew = wait_probe_time(env->anchors);
1884238106Sdes	anchors_init_parents_locked(env->anchors);
1885238106Sdes	lock_basic_unlock(&env->anchors->lock);
1886238106Sdes
1887249141Sdes	/* if !del_tp then the trust point is no longer present in the tree,
1888249141Sdes	 * it was deleted by someone else, who will write the zonefile and
1889249141Sdes	 * clean up the structure */
1890249141Sdes	if(del_tp) {
1891249141Sdes		/* save on disk */
1892249141Sdes		del_tp->autr->next_probe_time = 0; /* no more probing for it */
1893249141Sdes		autr_write_file(env, del_tp);
1894238106Sdes
1895249141Sdes		/* delete */
1896249141Sdes		autr_point_delete(del_tp);
1897249141Sdes	}
1898238106Sdes	if(mold != mnew) {
1899238106Sdes		reset_worker_timer(env);
1900238106Sdes	}
1901238106Sdes}
1902238106Sdes
1903238106Sdesint autr_process_prime(struct module_env* env, struct val_env* ve,
1904238106Sdes	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset)
1905238106Sdes{
1906238106Sdes	int changed = 0;
1907238106Sdes	log_assert(tp && tp->autr);
1908238106Sdes	/* autotrust update trust anchors */
1909238106Sdes	/* the tp is locked, and stays locked unless it is deleted */
1910238106Sdes
1911238106Sdes	/* we could just catch the anchor here while another thread
1912238106Sdes	 * is busy deleting it. Just unlock and let the other do its job */
1913238106Sdes	if(tp->autr->revoked) {
1914238106Sdes		log_nametypeclass(VERB_ALGO, "autotrust not processed, "
1915238106Sdes			"trust point revoked", tp->name,
1916238106Sdes			LDNS_RR_TYPE_DNSKEY, tp->dclass);
1917238106Sdes		lock_basic_unlock(&tp->lock);
1918238106Sdes		return 0; /* it is revoked */
1919238106Sdes	}
1920238106Sdes
1921238106Sdes	/* query_dnskeys(): */
1922238106Sdes	tp->autr->last_queried = *env->now;
1923238106Sdes
1924238106Sdes	log_nametypeclass(VERB_ALGO, "autotrust process for",
1925238106Sdes		tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
1926238106Sdes	/* see if time alone makes some keys valid */
1927238106Sdes	autr_holddown_exceed(env, tp, &changed);
1928238106Sdes	if(changed) {
1929238106Sdes		verbose(VERB_ALGO, "autotrust: morekeys, reassemble");
1930238106Sdes		if(!autr_assemble(tp)) {
1931238106Sdes			log_err("malloc failure assembling autotrust keys");
1932238106Sdes			return 1; /* unchanged */
1933238106Sdes		}
1934238106Sdes	}
1935238106Sdes	/* did we get any data? */
1936238106Sdes	if(!dnskey_rrset) {
1937238106Sdes		verbose(VERB_ALGO, "autotrust: no dnskey rrset");
1938238106Sdes		/* no update of query_failed, because then we would have
1939238106Sdes		 * to write to disk. But we cannot because we maybe are
1940238106Sdes		 * still 'initialising' with DS records, that we cannot write
1941238106Sdes		 * in the full format (which only contains KSKs). */
1942238106Sdes		return 1; /* trust point exists */
1943238106Sdes	}
1944238106Sdes	/* check for revoked keys to remove immediately */
1945238106Sdes	check_contains_revoked(env, ve, tp, dnskey_rrset, &changed);
1946238106Sdes	if(changed) {
1947238106Sdes		verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
1948238106Sdes		if(!autr_assemble(tp)) {
1949238106Sdes			log_err("malloc failure assembling autotrust keys");
1950238106Sdes			return 1; /* unchanged */
1951238106Sdes		}
1952238106Sdes		if(!tp->ds_rrset && !tp->dnskey_rrset) {
1953238106Sdes			/* no more keys, all are revoked */
1954238106Sdes			/* this is a success for this probe attempt */
1955238106Sdes			tp->autr->last_success = *env->now;
1956238106Sdes			autr_tp_remove(env, tp, dnskey_rrset);
1957238106Sdes			return 0; /* trust point removed */
1958238106Sdes		}
1959238106Sdes	}
1960238106Sdes	/* verify the dnskey rrset and see if it is valid. */
1961238106Sdes	if(!verify_dnskey(env, ve, tp, dnskey_rrset)) {
1962238106Sdes		verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
1963238106Sdes		/* only increase failure count if this is not the first prime,
1964238106Sdes		 * this means there was a previous succesful probe */
1965238106Sdes		if(tp->autr->last_success) {
1966238106Sdes			tp->autr->query_failed += 1;
1967238106Sdes			autr_write_file(env, tp);
1968238106Sdes		}
1969238106Sdes		return 1; /* trust point exists */
1970238106Sdes	}
1971238106Sdes
1972238106Sdes	tp->autr->last_success = *env->now;
1973238106Sdes	tp->autr->query_failed = 0;
1974238106Sdes
1975238106Sdes	/* Add new trust anchors to the data structure
1976238106Sdes	 * - note which trust anchors are seen this probe.
1977238106Sdes	 * Set trustpoint query_interval and retry_time.
1978238106Sdes	 * - find minimum rrsig expiration interval
1979238106Sdes	 */
1980238106Sdes	if(!update_events(env, ve, tp, dnskey_rrset, &changed)) {
1981238106Sdes		log_err("malloc failure in autotrust update_events. "
1982238106Sdes			"trust point unchanged.");
1983238106Sdes		return 1; /* trust point unchanged, so exists */
1984238106Sdes	}
1985238106Sdes
1986238106Sdes	/* - for every SEP key do the 5011 statetable.
1987238106Sdes	 * - remove missing trustanchors (if veryold and we have new anchors).
1988238106Sdes	 */
1989238106Sdes	if(!do_statetable(env, tp, &changed)) {
1990238106Sdes		log_err("malloc failure in autotrust do_statetable. "
1991238106Sdes			"trust point unchanged.");
1992238106Sdes		return 1; /* trust point unchanged, so exists */
1993238106Sdes	}
1994238106Sdes
1995238106Sdes	autr_cleanup_keys(tp);
1996238106Sdes	if(!set_next_probe(env, tp, dnskey_rrset))
1997238106Sdes		return 0; /* trust point does not exist */
1998238106Sdes	autr_write_file(env, tp);
1999238106Sdes	if(changed) {
2000238106Sdes		verbose(VERB_ALGO, "autotrust: changed, reassemble");
2001238106Sdes		if(!autr_assemble(tp)) {
2002238106Sdes			log_err("malloc failure assembling autotrust keys");
2003238106Sdes			return 1; /* unchanged */
2004238106Sdes		}
2005238106Sdes		if(!tp->ds_rrset && !tp->dnskey_rrset) {
2006238106Sdes			/* no more keys, all are revoked */
2007238106Sdes			autr_tp_remove(env, tp, dnskey_rrset);
2008238106Sdes			return 0; /* trust point removed */
2009238106Sdes		}
2010238106Sdes	} else verbose(VERB_ALGO, "autotrust: no changes");
2011238106Sdes
2012238106Sdes	return 1; /* trust point exists */
2013238106Sdes}
2014238106Sdes
2015238106Sdes/** debug print a trust anchor key */
2016238106Sdesstatic void
2017238106Sdesautr_debug_print_ta(struct autr_ta* ta)
2018238106Sdes{
2019238106Sdes	char buf[32];
2020238106Sdes	char* str = ldns_rr2str(ta->rr);
2021238106Sdes	if(!str) {
2022238106Sdes		log_info("out of memory in debug_print_ta");
2023238106Sdes		return;
2024238106Sdes	}
2025238106Sdes	if(str && str[0]) str[strlen(str)-1]=0; /* remove newline */
2026238106Sdes	ctime_r(&ta->last_change, buf);
2027238106Sdes	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
2028238106Sdes	log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s",
2029238106Sdes		trustanchor_state2str(ta->s), str, ta->s, ta->pending_count,
2030238106Sdes		ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf);
2031238106Sdes	free(str);
2032238106Sdes}
2033238106Sdes
2034238106Sdes/** debug print a trust point */
2035238106Sdesstatic void
2036238106Sdesautr_debug_print_tp(struct trust_anchor* tp)
2037238106Sdes{
2038238106Sdes	struct autr_ta* ta;
2039238106Sdes	char buf[257];
2040238106Sdes	if(!tp->autr)
2041238106Sdes		return;
2042238106Sdes	dname_str(tp->name, buf);
2043238106Sdes	log_info("trust point %s : %d", buf, (int)tp->dclass);
2044238106Sdes	log_info("assembled %d DS and %d DNSKEYs",
2045238106Sdes		(int)tp->numDS, (int)tp->numDNSKEY);
2046238106Sdes	if(0) { /* turned off because it prints to stderr */
2047238106Sdes		ldns_buffer* bf = ldns_buffer_new(70000);
2048238106Sdes		ldns_rr_list* list;
2049238106Sdes		if(tp->ds_rrset) {
2050238106Sdes			list = packed_rrset_to_rr_list(tp->ds_rrset, bf);
2051238106Sdes			ldns_rr_list_print(stderr, list);
2052238106Sdes			ldns_rr_list_deep_free(list);
2053238106Sdes		}
2054238106Sdes		if(tp->dnskey_rrset) {
2055238106Sdes			list = packed_rrset_to_rr_list(tp->dnskey_rrset, bf);
2056238106Sdes			ldns_rr_list_print(stderr, list);
2057238106Sdes			ldns_rr_list_deep_free(list);
2058238106Sdes		}
2059238106Sdes		ldns_buffer_free(bf);
2060238106Sdes	}
2061238106Sdes	log_info("file %s", tp->autr->file);
2062238106Sdes	ctime_r(&tp->autr->last_queried, buf);
2063238106Sdes	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
2064238106Sdes	log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf);
2065238106Sdes	ctime_r(&tp->autr->last_success, buf);
2066238106Sdes	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
2067238106Sdes	log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf);
2068238106Sdes	ctime_r(&tp->autr->next_probe_time, buf);
2069238106Sdes	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
2070238106Sdes	log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time,
2071238106Sdes		buf);
2072238106Sdes	log_info("query_interval: %u", (unsigned)tp->autr->query_interval);
2073238106Sdes	log_info("retry_time: %u", (unsigned)tp->autr->retry_time);
2074238106Sdes	log_info("query_failed: %u", (unsigned)tp->autr->query_failed);
2075238106Sdes
2076238106Sdes	for(ta=tp->autr->keys; ta; ta=ta->next) {
2077238106Sdes		autr_debug_print_ta(ta);
2078238106Sdes	}
2079238106Sdes}
2080238106Sdes
2081238106Sdesvoid
2082238106Sdesautr_debug_print(struct val_anchors* anchors)
2083238106Sdes{
2084238106Sdes	struct trust_anchor* tp;
2085238106Sdes	lock_basic_lock(&anchors->lock);
2086238106Sdes	RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) {
2087238106Sdes		lock_basic_lock(&tp->lock);
2088238106Sdes		autr_debug_print_tp(tp);
2089238106Sdes		lock_basic_unlock(&tp->lock);
2090238106Sdes	}
2091238106Sdes	lock_basic_unlock(&anchors->lock);
2092238106Sdes}
2093238106Sdes
2094238106Sdesvoid probe_answer_cb(void* arg, int ATTR_UNUSED(rcode),
2095238106Sdes	ldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec),
2096238106Sdes	char* ATTR_UNUSED(why_bogus))
2097238106Sdes{
2098238106Sdes	/* retry was set before the query was done,
2099238106Sdes	 * re-querytime is set when query succeeded, but that may not
2100238106Sdes	 * have reset this timer because the query could have been
2101238106Sdes	 * handled by another thread. In that case, this callback would
2102238106Sdes	 * get called after the original timeout is done.
2103238106Sdes	 * By not resetting the timer, it may probe more often, but not
2104238106Sdes	 * less often.
2105238106Sdes	 * Unless the new lookup resulted in smaller TTLs and thus smaller
2106238106Sdes	 * timeout values. In that case one old TTL could be mistakenly done.
2107238106Sdes	 */
2108238106Sdes	struct module_env* env = (struct module_env*)arg;
2109238106Sdes	verbose(VERB_ALGO, "autotrust probe answer cb");
2110238106Sdes	reset_worker_timer(env);
2111238106Sdes}
2112238106Sdes
2113238106Sdes/** probe a trust anchor DNSKEY and unlocks tp */
2114238106Sdesstatic void
2115238106Sdesprobe_anchor(struct module_env* env, struct trust_anchor* tp)
2116238106Sdes{
2117238106Sdes	struct query_info qinfo;
2118238106Sdes	uint16_t qflags = BIT_RD;
2119238106Sdes	struct edns_data edns;
2120238106Sdes	ldns_buffer* buf = env->scratch_buffer;
2121238106Sdes	qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen);
2122238106Sdes	if(!qinfo.qname) {
2123238106Sdes		log_err("out of memory making 5011 probe");
2124238106Sdes		return;
2125238106Sdes	}
2126238106Sdes	qinfo.qname_len = tp->namelen;
2127238106Sdes	qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
2128238106Sdes	qinfo.qclass = tp->dclass;
2129238106Sdes	log_query_info(VERB_ALGO, "autotrust probe", &qinfo);
2130238106Sdes	verbose(VERB_ALGO, "retry probe set in %d seconds",
2131238106Sdes		(int)tp->autr->next_probe_time - (int)*env->now);
2132238106Sdes	edns.edns_present = 1;
2133238106Sdes	edns.ext_rcode = 0;
2134238106Sdes	edns.edns_version = 0;
2135238106Sdes	edns.bits = EDNS_DO;
2136238106Sdes	if(ldns_buffer_capacity(buf) < 65535)
2137238106Sdes		edns.udp_size = (uint16_t)ldns_buffer_capacity(buf);
2138238106Sdes	else	edns.udp_size = 65535;
2139238106Sdes
2140238106Sdes	/* can't hold the lock while mesh_run is processing */
2141238106Sdes	lock_basic_unlock(&tp->lock);
2142238106Sdes
2143238106Sdes	/* delete the DNSKEY from rrset and key cache so an active probe
2144238106Sdes	 * is done. First the rrset so another thread does not use it
2145238106Sdes	 * to recreate the key entry in a race condition. */
2146238106Sdes	rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len,
2147238106Sdes		qinfo.qtype, qinfo.qclass, 0);
2148238106Sdes	key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len,
2149238106Sdes		qinfo.qclass);
2150238106Sdes
2151238106Sdes	if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
2152238106Sdes		&probe_answer_cb, env)) {
2153238106Sdes		log_err("out of memory making 5011 probe");
2154238106Sdes	}
2155238106Sdes}
2156238106Sdes
2157238106Sdes/** fetch first to-probe trust-anchor and lock it and set retrytime */
2158238106Sdesstatic struct trust_anchor*
2159238106Sdestodo_probe(struct module_env* env, uint32_t* next)
2160238106Sdes{
2161238106Sdes	struct trust_anchor* tp;
2162238106Sdes	rbnode_t* el;
2163238106Sdes	/* get first one */
2164238106Sdes	lock_basic_lock(&env->anchors->lock);
2165238106Sdes	if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) {
2166238106Sdes		/* in case of revoked anchors */
2167238106Sdes		lock_basic_unlock(&env->anchors->lock);
2168238106Sdes		return NULL;
2169238106Sdes	}
2170238106Sdes	tp = (struct trust_anchor*)el->key;
2171238106Sdes	lock_basic_lock(&tp->lock);
2172238106Sdes
2173238106Sdes	/* is it eligible? */
2174238106Sdes	if((uint32_t)tp->autr->next_probe_time > *env->now) {
2175238106Sdes		/* no more to probe */
2176238106Sdes		*next = (uint32_t)tp->autr->next_probe_time - *env->now;
2177238106Sdes		lock_basic_unlock(&tp->lock);
2178238106Sdes		lock_basic_unlock(&env->anchors->lock);
2179238106Sdes		return NULL;
2180238106Sdes	}
2181238106Sdes
2182238106Sdes	/* reset its next probe time */
2183238106Sdes	(void)rbtree_delete(&env->anchors->autr->probe, tp);
2184238106Sdes	tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time);
2185238106Sdes	(void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
2186238106Sdes	lock_basic_unlock(&env->anchors->lock);
2187238106Sdes
2188238106Sdes	return tp;
2189238106Sdes}
2190238106Sdes
2191238106Sdesuint32_t
2192238106Sdesautr_probe_timer(struct module_env* env)
2193238106Sdes{
2194238106Sdes	struct trust_anchor* tp;
2195238106Sdes	uint32_t next_probe = 3600;
2196238106Sdes	int num = 0;
2197238106Sdes	verbose(VERB_ALGO, "autotrust probe timer callback");
2198238106Sdes	/* while there are still anchors to probe */
2199238106Sdes	while( (tp = todo_probe(env, &next_probe)) ) {
2200238106Sdes		/* make a probe for this anchor */
2201238106Sdes		probe_anchor(env, tp);
2202238106Sdes		num++;
2203238106Sdes	}
2204238106Sdes	regional_free_all(env->scratch);
2205238106Sdes	if(num == 0)
2206238106Sdes		return 0; /* no trust points to probe */
2207238106Sdes	verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num);
2208238106Sdes	return next_probe;
2209238106Sdes}
2210