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