Coverage Report

Created: 2025-07-29 06:50

/src/unbound/validator/val_anchor.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * validator/val_anchor.c - validator trust anchor storage.
3
 *
4
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5
 *
6
 * This software is open source.
7
 * 
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 
12
 * Redistributions of source code must retain the above copyright notice,
13
 * this list of conditions and the following disclaimer.
14
 * 
15
 * Redistributions in binary form must reproduce the above copyright notice,
16
 * this list of conditions and the following disclaimer in the documentation
17
 * and/or other materials provided with the distribution.
18
 * 
19
 * Neither the name of the NLNET LABS nor the names of its contributors may
20
 * be used to endorse or promote products derived from this software without
21
 * specific prior written permission.
22
 * 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
35
36
/**
37
 * \file
38
 *
39
 * This file contains storage for the trust anchors for the validator.
40
 */
41
#include "config.h"
42
#include <ctype.h>
43
#include "validator/val_anchor.h"
44
#include "validator/val_sigcrypt.h"
45
#include "validator/autotrust.h"
46
#include "util/data/packed_rrset.h"
47
#include "util/data/dname.h"
48
#include "util/log.h"
49
#include "util/net_help.h"
50
#include "util/config_file.h"
51
#include "util/as112.h"
52
#include "sldns/sbuffer.h"
53
#include "sldns/rrdef.h"
54
#include "sldns/str2wire.h"
55
#ifdef HAVE_GLOB_H
56
#include <glob.h>
57
#endif
58
59
int
60
anchor_cmp(const void* k1, const void* k2)
61
0
{
62
0
  int m;
63
0
  struct trust_anchor* n1 = (struct trust_anchor*)k1;
64
0
  struct trust_anchor* n2 = (struct trust_anchor*)k2;
65
  /* no need to ntohs(class) because sort order is irrelevant */
66
0
  if(n1->dclass != n2->dclass) {
67
0
    if(n1->dclass < n2->dclass)
68
0
      return -1;
69
0
    return 1;
70
0
  }
71
0
  return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs, 
72
0
    &m);
73
0
}
74
75
struct val_anchors* 
76
anchors_create(void)
77
0
{
78
0
  struct val_anchors* a = (struct val_anchors*)calloc(1, sizeof(*a));
79
0
  if(!a)
80
0
    return NULL;
81
0
  a->tree = rbtree_create(anchor_cmp);
82
0
  if(!a->tree) {
83
0
    anchors_delete(a);
84
0
    return NULL;
85
0
  }
86
0
  a->autr = autr_global_create();
87
0
  if(!a->autr) {
88
0
    anchors_delete(a);
89
0
    return NULL;
90
0
  }
91
0
  lock_basic_init(&a->lock);
92
0
  lock_protect(&a->lock, a, sizeof(*a));
93
0
  lock_protect(&a->lock, a->autr, sizeof(*a->autr));
94
0
  return a;
95
0
}
96
97
/** delete assembled rrset */
98
static void
99
assembled_rrset_delete(struct ub_packed_rrset_key* pkey)
100
0
{
101
0
  if(!pkey) return;
102
0
  if(pkey->entry.data) {
103
0
    struct packed_rrset_data* pd = (struct packed_rrset_data*)
104
0
      pkey->entry.data;
105
0
    free(pd->rr_data);
106
0
    free(pd->rr_ttl);
107
0
    free(pd->rr_len);
108
0
    free(pd);
109
0
  }
110
0
  free(pkey->rk.dname);
111
0
  free(pkey);
112
0
}
113
114
/** destroy locks in tree and delete autotrust anchors */
115
static void
116
anchors_delfunc(rbnode_type* elem, void* ATTR_UNUSED(arg))
117
0
{
118
0
  struct trust_anchor* ta = (struct trust_anchor*)elem;
119
0
  if(!ta) return;
120
0
  if(ta->autr) {
121
0
    autr_point_delete(ta);
122
0
  } else {
123
0
    struct ta_key* p, *np;
124
0
    lock_basic_destroy(&ta->lock);
125
0
    free(ta->name);
126
0
    p = ta->keylist;
127
0
    while(p) {
128
0
      np = p->next;
129
0
      free(p->data);
130
0
      free(p);
131
0
      p = np;
132
0
    }
133
0
    assembled_rrset_delete(ta->ds_rrset);
134
0
    assembled_rrset_delete(ta->dnskey_rrset);
135
0
    free(ta);
136
0
  }
137
0
}
138
139
void 
140
anchors_delete(struct val_anchors* anchors)
141
0
{
142
0
  if(!anchors)
143
0
    return;
144
0
  lock_unprotect(&anchors->lock, anchors->autr);
145
0
  lock_unprotect(&anchors->lock, anchors);
146
0
  lock_basic_destroy(&anchors->lock);
147
0
  if(anchors->tree)
148
0
    traverse_postorder(anchors->tree, anchors_delfunc, NULL);
149
0
  free(anchors->tree);
150
0
  autr_global_delete(anchors->autr);
151
0
  free(anchors);
152
0
}
153
154
void
155
anchors_init_parents_locked(struct val_anchors* anchors)
156
0
{
157
0
  struct trust_anchor* node, *prev = NULL, *p;
158
0
  int m; 
159
  /* nobody else can grab locks because we hold the main lock.
160
   * Thus the previous items, after unlocked, are not deleted */
161
0
  RBTREE_FOR(node, struct trust_anchor*, anchors->tree) {
162
0
    lock_basic_lock(&node->lock);
163
0
    node->parent = NULL;
164
0
    if(!prev || prev->dclass != node->dclass) {
165
0
      prev = node;
166
0
      lock_basic_unlock(&node->lock);
167
0
      continue;
168
0
    }
169
0
    (void)dname_lab_cmp(prev->name, prev->namelabs, node->name, 
170
0
      node->namelabs, &m); /* we know prev is smaller */
171
    /* sort order like: . com. bla.com. zwb.com. net. */
172
    /* find the previous, or parent-parent-parent */
173
0
    for(p = prev; p; p = p->parent)
174
      /* looking for name with few labels, a parent */
175
0
      if(p->namelabs <= m) {
176
        /* ==: since prev matched m, this is closest*/
177
        /* <: prev matches more, but is not a parent,
178
        * this one is a (grand)parent */
179
0
        node->parent = p;
180
0
        break;
181
0
      }
182
0
    lock_basic_unlock(&node->lock);
183
0
    prev = node;
184
0
  }
185
0
}
186
187
/** initialise parent pointers in the tree */
188
static void
189
init_parents(struct val_anchors* anchors)
190
0
{
191
0
  lock_basic_lock(&anchors->lock);
192
0
  anchors_init_parents_locked(anchors);
193
0
  lock_basic_unlock(&anchors->lock);
194
0
}
195
196
struct trust_anchor*
197
anchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs,
198
  size_t namelen, uint16_t dclass)
199
0
{
200
0
  struct trust_anchor key;
201
0
  rbnode_type* n;
202
0
  if(!name) return NULL;
203
0
  key.node.key = &key;
204
0
  key.name = name;
205
0
  key.namelabs = namelabs;
206
0
  key.namelen = namelen;
207
0
  key.dclass = dclass;
208
0
  lock_basic_lock(&anchors->lock);
209
0
  n = rbtree_search(anchors->tree, &key);
210
0
  if(n) {
211
0
    lock_basic_lock(&((struct trust_anchor*)n->key)->lock);
212
0
  }
213
0
  lock_basic_unlock(&anchors->lock);
214
0
  if(!n)
215
0
    return NULL;
216
0
  return (struct trust_anchor*)n->key;
217
0
}
218
219
/** create new trust anchor object */
220
static struct trust_anchor*
221
anchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs,
222
  size_t namelen, uint16_t dclass, int lockit)
223
0
{
224
#ifdef UNBOUND_DEBUG
225
  rbnode_type* r;
226
#endif
227
0
  struct trust_anchor* ta = (struct trust_anchor*)malloc(
228
0
    sizeof(struct trust_anchor));
229
0
  if(!ta)
230
0
    return NULL;
231
0
  memset(ta, 0, sizeof(*ta));
232
0
  ta->node.key = ta;
233
0
  ta->name = memdup(name, namelen);
234
0
  if(!ta->name) {
235
0
    free(ta);
236
0
    return NULL;
237
0
  }
238
0
  ta->namelabs = namelabs;
239
0
  ta->namelen = namelen;
240
0
  ta->dclass = dclass;
241
0
  lock_basic_init(&ta->lock);
242
0
  if(lockit) {
243
0
    lock_basic_lock(&anchors->lock);
244
0
  }
245
#ifdef UNBOUND_DEBUG
246
  r =
247
#else
248
0
  (void)
249
0
#endif
250
0
  rbtree_insert(anchors->tree, &ta->node);
251
0
  if(lockit) {
252
0
    lock_basic_unlock(&anchors->lock);
253
0
  }
254
0
  log_assert(r != NULL);
255
0
  return ta;
256
0
}
257
258
/** find trustanchor key by exact data match */
259
static struct ta_key*
260
anchor_find_key(struct trust_anchor* ta, uint8_t* rdata, size_t rdata_len,
261
  uint16_t type)
262
0
{
263
0
  struct ta_key* k;
264
0
  for(k = ta->keylist; k; k = k->next) {
265
0
    if(k->type == type && k->len == rdata_len &&
266
0
      memcmp(k->data, rdata, rdata_len) == 0)
267
0
      return k;
268
0
  }
269
0
  return NULL;
270
0
}
271
  
272
/** create new trustanchor key */
273
static struct ta_key*
274
anchor_new_ta_key(uint8_t* rdata, size_t rdata_len, uint16_t type)
275
0
{
276
0
  struct ta_key* k = (struct ta_key*)malloc(sizeof(*k));
277
0
  if(!k)
278
0
    return NULL;
279
0
  memset(k, 0, sizeof(*k));
280
0
  k->data = memdup(rdata, rdata_len);
281
0
  if(!k->data) {
282
0
    free(k);
283
0
    return NULL;
284
0
  }
285
0
  k->len = rdata_len;
286
0
  k->type = type;
287
0
  return k;
288
0
}
289
290
/**
291
 * This routine adds a new RR to a trust anchor. The trust anchor may not
292
 * exist yet, and is created if not. The RR can be DS or DNSKEY.
293
 * This routine will also remove duplicates; storing them only once.
294
 * @param anchors: anchor storage.
295
 * @param name: name of trust anchor (wireformat)
296
 * @param type: type or RR
297
 * @param dclass: class of RR
298
 * @param rdata: rdata wireformat, starting with rdlength.
299
 *  If NULL, nothing is stored, but an entry is created.
300
 * @param rdata_len: length of rdata including rdlength.
301
 * @return: NULL on error, else the trust anchor.
302
 */
303
static struct trust_anchor*
304
anchor_store_new_key(struct val_anchors* anchors, uint8_t* name, uint16_t type,
305
  uint16_t dclass, uint8_t* rdata, size_t rdata_len)
306
0
{
307
0
  struct ta_key* k;
308
0
  struct trust_anchor* ta;
309
0
  int namelabs;
310
0
  size_t namelen;
311
0
  namelabs = dname_count_size_labels(name, &namelen);
312
0
  if(type != LDNS_RR_TYPE_DS && type != LDNS_RR_TYPE_DNSKEY) {
313
0
    log_err("Bad type for trust anchor");
314
0
    return 0;
315
0
  }
316
  /* lookup or create trustanchor */
317
0
  ta = anchor_find(anchors, name, namelabs, namelen, dclass);
318
0
  if(!ta) {
319
0
    ta = anchor_new_ta(anchors, name, namelabs, namelen, dclass, 1);
320
0
    if(!ta)
321
0
      return NULL;
322
0
    lock_basic_lock(&ta->lock);
323
0
  }
324
0
  if(!rdata) {
325
0
    lock_basic_unlock(&ta->lock);
326
0
    return ta;
327
0
  }
328
  /* look for duplicates */
329
0
  if(anchor_find_key(ta, rdata, rdata_len, type)) {
330
0
    lock_basic_unlock(&ta->lock);
331
0
    return ta;
332
0
  }
333
0
  k = anchor_new_ta_key(rdata, rdata_len, type);
334
0
  if(!k) {
335
0
    lock_basic_unlock(&ta->lock);
336
0
    return NULL;
337
0
  }
338
  /* add new key */
339
0
  if(type == LDNS_RR_TYPE_DS)
340
0
    ta->numDS++;
341
0
  else  ta->numDNSKEY++;
342
0
  k->next = ta->keylist;
343
0
  ta->keylist = k;
344
0
  lock_basic_unlock(&ta->lock);
345
0
  return ta;
346
0
}
347
348
/**
349
 * Add new RR. It converts ldns RR to wire format.
350
 * @param anchors: anchor storage.
351
 * @param rr: the wirerr.
352
 * @param rl: length of rr.
353
 * @param dl: length of dname.
354
 * @return NULL on error, else the trust anchor.
355
 */
356
static struct trust_anchor*
357
anchor_store_new_rr(struct val_anchors* anchors, uint8_t* rr, size_t rl,
358
  size_t dl)
359
0
{
360
0
  struct trust_anchor* ta;
361
0
  if(!(ta=anchor_store_new_key(anchors, rr,
362
0
    sldns_wirerr_get_type(rr, rl, dl),
363
0
    sldns_wirerr_get_class(rr, rl, dl),
364
0
    sldns_wirerr_get_rdatawl(rr, rl, dl),
365
0
    sldns_wirerr_get_rdatalen(rr, rl, dl)+2))) {
366
0
    return NULL;
367
0
  }
368
0
  log_nametypeclass(VERB_QUERY, "adding trusted key",
369
0
    rr, sldns_wirerr_get_type(rr, rl, dl),
370
0
    sldns_wirerr_get_class(rr, rl, dl));
371
0
  return ta;
372
0
}
373
374
/**
375
 * Insert insecure anchor
376
 * @param anchors: anchor storage.
377
 * @param str: the domain name.
378
 * @return NULL on error, Else last trust anchor point
379
 */
380
static struct trust_anchor*
381
anchor_insert_insecure(struct val_anchors* anchors, const char* str)
382
0
{
383
0
  struct trust_anchor* ta;
384
0
  size_t dname_len = 0;
385
0
  uint8_t* nm = sldns_str2wire_dname(str, &dname_len);
386
0
  if(!nm) {
387
0
    log_err("parse error in domain name '%s'", str);
388
0
    return NULL;
389
0
  }
390
0
  ta = anchor_store_new_key(anchors, nm, LDNS_RR_TYPE_DS,
391
0
    LDNS_RR_CLASS_IN, NULL, 0);
392
0
  free(nm);
393
0
  return ta;
394
0
}
395
396
struct trust_anchor*
397
anchor_store_str(struct val_anchors* anchors, sldns_buffer* buffer,
398
  const char* str)
399
0
{
400
0
  struct trust_anchor* ta;
401
0
  uint8_t* rr = sldns_buffer_begin(buffer);
402
0
  size_t len = sldns_buffer_capacity(buffer), dname_len = 0;
403
0
  int status = sldns_str2wire_rr_buf(str, rr, &len, &dname_len,
404
0
    0, NULL, 0, NULL, 0);
405
0
  if(status != 0) {
406
0
    log_err("error parsing trust anchor %s: at %d: %s", 
407
0
      str, LDNS_WIREPARSE_OFFSET(status),
408
0
      sldns_get_errorstr_parse(status));
409
0
    return NULL;
410
0
  }
411
0
  if(!(ta=anchor_store_new_rr(anchors, rr, len, dname_len))) {
412
0
    log_err("out of memory");
413
0
    return NULL;
414
0
  }
415
0
  return ta;
416
0
}
417
418
/**
419
 * Read a file with trust anchors
420
 * @param anchors: anchor storage.
421
 * @param buffer: parsing buffer.
422
 * @param fname: string.
423
 * @param onlyone: only one trust anchor allowed in file.
424
 * @return NULL on error. Else last trust-anchor point.
425
 */
426
static struct trust_anchor*
427
anchor_read_file(struct val_anchors* anchors, sldns_buffer* buffer,
428
  const char* fname, int onlyone)
429
0
{
430
0
  struct trust_anchor* ta = NULL, *tanew;
431
0
  struct sldns_file_parse_state pst;
432
0
  int status;
433
0
  size_t len, dname_len;
434
0
  uint8_t* rr = sldns_buffer_begin(buffer);
435
0
  int ok = 1;
436
0
  FILE* in = fopen(fname, "r");
437
0
  if(!in) {
438
0
    log_err("error opening file %s: %s", fname, strerror(errno));
439
0
    return 0;
440
0
  }
441
0
  memset(&pst, 0, sizeof(pst));
442
0
  pst.default_ttl = 3600;
443
0
  pst.lineno = 1;
444
0
  while(!feof(in)) {
445
0
    len = sldns_buffer_capacity(buffer);
446
0
    dname_len = 0;
447
0
    status = sldns_fp2wire_rr_buf(in, rr, &len, &dname_len, &pst);
448
0
    if(len == 0) /* empty, $TTL, $ORIGIN */
449
0
      continue;
450
0
    if(status != 0) {
451
0
      log_err("parse error in %s:%d:%d : %s", fname,
452
0
        pst.lineno, LDNS_WIREPARSE_OFFSET(status),
453
0
        sldns_get_errorstr_parse(status));
454
0
      ok = 0;
455
0
      break;
456
0
    }
457
0
    if(sldns_wirerr_get_type(rr, len, dname_len) !=
458
0
      LDNS_RR_TYPE_DS && sldns_wirerr_get_type(rr, len,
459
0
      dname_len) != LDNS_RR_TYPE_DNSKEY) {
460
0
      continue;
461
0
    }
462
0
    if(!(tanew=anchor_store_new_rr(anchors, rr, len, dname_len))) {
463
0
      log_err("mem error at %s line %d", fname, pst.lineno);
464
0
      ok = 0;
465
0
      break;
466
0
    }
467
0
    if(onlyone && ta && ta != tanew) {
468
0
      log_err("error at %s line %d: no multiple anchor "
469
0
        "domains allowed (you can have multiple "
470
0
        "keys, but they must have the same name).", 
471
0
        fname, pst.lineno);
472
0
      ok = 0;
473
0
      break;
474
0
    }
475
0
    ta = tanew;
476
0
  }
477
0
  fclose(in);
478
0
  if(!ok) return NULL;
479
  /* empty file is OK when multiple anchors are allowed */
480
0
  if(!onlyone && !ta) return (struct trust_anchor*)1;
481
0
  return ta;
482
0
}
483
484
/** skip file to end of line */
485
static void
486
skip_to_eol(FILE* in, int *c)
487
0
{
488
0
  while((*c = getc(in)) != EOF ) {
489
0
    if(*c == '\n')
490
0
      return;
491
0
  }
492
0
}
493
494
/** true for special characters in bind configs */
495
static int
496
is_bind_special(int c)
497
0
{
498
0
  switch(c) {
499
0
    case '{':
500
0
    case '}':
501
0
    case '"':
502
0
    case ';':
503
0
      return 1;
504
0
  }
505
0
  return 0;
506
0
}
507
508
/** 
509
 * Read a keyword skipping bind comments; spaces, specials, restkeywords. 
510
 * The file is split into the following tokens:
511
 *  * special characters, on their own, rdlen=1, { } doublequote ;
512
 *  * whitespace becomes a single ' ' or tab. Newlines become spaces.
513
 *  * other words ('keywords')
514
 *  * comments are skipped if desired
515
 *    / / C++ style comment to end of line
516
 *    # to end of line
517
 *    / * C style comment * /
518
 * @param in: file to read from.
519
 * @param buf: buffer, what is read is stored after current buffer position.
520
 *  Space is left in the buffer to write a terminating 0.
521
 * @param line: line number is increased per line, for error reports.
522
 * @param comments: if 0, comments are not possible and become text.
523
 *  if 1, comments are skipped entirely.
524
 *  In BIND files, this is when reading quoted strings, for example
525
 *  " base 64 text with / / in there "
526
 * @return the number of character written to the buffer. 
527
 *  0 on end of file.
528
 */
529
static int
530
readkeyword_bindfile(FILE* in, sldns_buffer* buf, int* line, int comments)
531
0
{
532
0
  int c;
533
0
  int numdone = 0;
534
0
  while((c = getc(in)) != EOF ) {
535
0
    if(comments && c == '#') { /*   # blabla   */
536
0
      skip_to_eol(in, &c);
537
0
      if(c == EOF) return 0;
538
0
      (*line)++;
539
0
      continue;
540
0
    } else if(comments && c=='/' && numdone>0 && /* /_/ bla*/
541
0
      sldns_buffer_read_u8_at(buf, 
542
0
      sldns_buffer_position(buf)-1) == '/') {
543
0
      sldns_buffer_skip(buf, -1);
544
0
      numdone--;
545
0
      skip_to_eol(in, &c);
546
0
      if(c == EOF) return 0;
547
0
      (*line)++;
548
0
      continue;
549
0
    } else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */
550
0
      sldns_buffer_read_u8_at(buf, 
551
0
      sldns_buffer_position(buf)-1) == '/') {
552
0
      sldns_buffer_skip(buf, -1);
553
0
      numdone--;
554
      /* skip to end of comment */
555
0
      while(c != EOF && (c=getc(in)) != EOF ) {
556
0
        if(c == '*') {
557
0
          if((c=getc(in)) == '/')
558
0
            break;
559
0
        }
560
0
        if(c == '\n')
561
0
          (*line)++;
562
0
      }
563
0
      if(c == EOF) return 0;
564
0
      continue;
565
0
    }
566
    /* not a comment, complete the keyword */
567
0
    if(numdone > 0) {
568
      /* check same type */
569
0
      if(isspace((unsigned char)c)) {
570
0
        ungetc(c, in);
571
0
        return numdone;
572
0
      }
573
0
      if(is_bind_special(c)) {
574
0
        ungetc(c, in);
575
0
        return numdone;
576
0
      }
577
0
    }
578
0
    if(c == '\n') {
579
0
      c = ' ';
580
0
      (*line)++;
581
0
    }
582
    /* space for 1 char + 0 string terminator */
583
0
    if(sldns_buffer_remaining(buf) < 2) {
584
0
      fatal_exit("trusted-keys, %d, string too long", *line);
585
0
    }
586
0
    sldns_buffer_write_u8(buf, (uint8_t)c);
587
0
    numdone++;
588
0
    if(isspace((unsigned char)c)) {
589
      /* collate whitespace into ' ' */
590
0
      while((c = getc(in)) != EOF ) {
591
0
        if(c == '\n')
592
0
          (*line)++;
593
0
        if(!isspace((unsigned char)c)) {
594
0
          ungetc(c, in);
595
0
          break;
596
0
        }
597
0
      }
598
0
      if(c == EOF) return 0;
599
0
      return numdone;
600
0
    }
601
0
    if(is_bind_special(c))
602
0
      return numdone;
603
0
  }
604
0
  return numdone;
605
0
}
606
607
/** skip through file to { or ; */
608
static int 
609
skip_to_special(FILE* in, sldns_buffer* buf, int* line, int spec) 
610
0
{
611
0
  int rdlen;
612
0
  sldns_buffer_clear(buf);
613
0
  while((rdlen=readkeyword_bindfile(in, buf, line, 1))) {
614
0
    if(rdlen == 1 && isspace((unsigned char)*sldns_buffer_begin(buf))) {
615
0
      sldns_buffer_clear(buf);
616
0
      continue;
617
0
    }
618
0
    if(rdlen != 1 || *sldns_buffer_begin(buf) != (uint8_t)spec) {
619
0
      sldns_buffer_write_u8(buf, 0);
620
0
      log_err("trusted-keys, line %d, expected %c", 
621
0
        *line, spec);
622
0
      return 0;
623
0
    }
624
0
    return 1;
625
0
  }
626
0
  log_err("trusted-keys, line %d, expected %c got EOF", *line, spec);
627
0
  return 0;
628
0
}
629
630
/** 
631
 * read contents of trusted-keys{ ... ; clauses and insert keys into storage.
632
 * @param anchors: where to store keys
633
 * @param buf: buffer to use
634
 * @param line: line number in file
635
 * @param in: file to read from.
636
 * @return 0 on error.
637
 */
638
static int
639
process_bind_contents(struct val_anchors* anchors, sldns_buffer* buf, 
640
  int* line, FILE* in)
641
0
{
642
  /* loop over contents, collate strings before ; */
643
  /* contents is (numbered): 0   1    2  3 4   5  6 7 8    */
644
  /*                           name. 257 3 5 base64 base64 */
645
  /* quoted value:           0 "111"  0  0 0   0  0 0 0    */
646
  /* comments value:         1 "000"  1  1  1 "0  0 0 0"  1 */
647
0
  int contnum = 0;
648
0
  int quoted = 0;
649
0
  int comments = 1;
650
0
  int rdlen;
651
0
  char* str = 0;
652
0
  sldns_buffer_clear(buf);
653
0
  while((rdlen=readkeyword_bindfile(in, buf, line, comments))) {
654
0
    if(rdlen == 1 && sldns_buffer_position(buf) == 1
655
0
      && isspace((unsigned char)*sldns_buffer_begin(buf))) {
656
      /* starting whitespace is removed */
657
0
      sldns_buffer_clear(buf);
658
0
      continue;
659
0
    } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '"') {
660
      /* remove " from the string */
661
0
      if(contnum == 0) {
662
0
        quoted = 1;
663
0
        comments = 0;
664
0
      }
665
0
      sldns_buffer_skip(buf, -1);
666
0
      if(contnum > 0 && quoted) {
667
0
        if(sldns_buffer_remaining(buf) < 8+1) {
668
0
          log_err("line %d, too long", *line);
669
0
          return 0;
670
0
        }
671
0
        sldns_buffer_write(buf, " DNSKEY ", 8);
672
0
        quoted = 0;
673
0
        comments = 1;
674
0
      } else if(contnum > 0)
675
0
        comments = !comments;
676
0
      continue;
677
0
    } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == ';') {
678
679
0
      if(contnum < 5) {
680
0
        sldns_buffer_write_u8(buf, 0);
681
0
        log_err("line %d, bad key", *line);
682
0
        return 0;
683
0
      }
684
0
      sldns_buffer_skip(buf, -1);
685
0
      sldns_buffer_write_u8(buf, 0);
686
0
      str = strdup((char*)sldns_buffer_begin(buf));
687
0
      if(!str) {
688
0
        log_err("line %d, allocation failure", *line);
689
0
        return 0;
690
0
      }
691
0
      if(!anchor_store_str(anchors, buf, str)) {
692
0
        log_err("line %d, bad key", *line);
693
0
        free(str);
694
0
        return 0;
695
0
      }
696
0
      free(str);
697
0
      sldns_buffer_clear(buf);
698
0
      contnum = 0;
699
0
      quoted = 0;
700
0
      comments = 1;
701
0
      continue;
702
0
    } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '}') {
703
0
      if(contnum > 0) {
704
0
        sldns_buffer_write_u8(buf, 0);
705
0
        log_err("line %d, bad key before }", *line);
706
0
        return 0;
707
0
      }
708
0
      return 1;
709
0
    } else if(rdlen == 1 && 
710
0
      isspace((unsigned char)sldns_buffer_current(buf)[-1])) {
711
      /* leave whitespace here */
712
0
    } else {
713
      /* not space or whatnot, so actual content */
714
0
      contnum ++;
715
0
      if(contnum == 1 && !quoted) {
716
0
        if(sldns_buffer_remaining(buf) < 8+1) {
717
0
          log_err("line %d, too long", *line);
718
0
          return 0;
719
0
        }  
720
0
        sldns_buffer_write(buf, " DNSKEY ", 8);
721
0
      }
722
0
    }
723
0
  }
724
725
0
  log_err("line %d, EOF before }", *line);
726
0
  return 0;
727
0
}
728
729
/**
730
 * Read a BIND9 like file with trust anchors in named.conf format.
731
 * @param anchors: anchor storage.
732
 * @param buffer: parsing buffer.
733
 * @param fname: string.
734
 * @return false on error.
735
 */
736
static int
737
anchor_read_bind_file(struct val_anchors* anchors, sldns_buffer* buffer,
738
  const char* fname)
739
0
{
740
0
  int line_nr = 1;
741
0
  FILE* in = fopen(fname, "r");
742
0
  int rdlen = 0;
743
0
  if(!in) {
744
0
    log_err("error opening file %s: %s", fname, strerror(errno));
745
0
    return 0;
746
0
  }
747
0
  verbose(VERB_QUERY, "reading in bind-compat-mode: '%s'", fname);
748
  /* scan for  trusted-keys  keyword, ignore everything else */
749
0
  sldns_buffer_clear(buffer);
750
0
  while((rdlen=readkeyword_bindfile(in, buffer, &line_nr, 1)) != 0) {
751
0
    if(rdlen != 12 || strncmp((char*)sldns_buffer_begin(buffer),
752
0
      "trusted-keys", 12) != 0) {
753
0
      sldns_buffer_clear(buffer);
754
      /* ignore everything but trusted-keys */
755
0
      continue;
756
0
    }
757
0
    if(!skip_to_special(in, buffer, &line_nr, '{')) {
758
0
      log_err("error in trusted key: \"%s\"", fname);
759
0
      fclose(in);
760
0
      return 0;
761
0
    }
762
    /* process contents */
763
0
    if(!process_bind_contents(anchors, buffer, &line_nr, in)) {
764
0
      log_err("error in trusted key: \"%s\"", fname);
765
0
      fclose(in);
766
0
      return 0;
767
0
    }
768
0
    if(!skip_to_special(in, buffer, &line_nr, ';')) {
769
0
      log_err("error in trusted key: \"%s\"", fname);
770
0
      fclose(in);
771
0
      return 0;
772
0
    }
773
0
    sldns_buffer_clear(buffer);
774
0
  }
775
0
  fclose(in);
776
0
  return 1;
777
0
}
778
779
/**
780
 * Read a BIND9 like files with trust anchors in named.conf format.
781
 * Performs wildcard processing of name.
782
 * @param anchors: anchor storage.
783
 * @param buffer: parsing buffer.
784
 * @param pat: pattern string. (can be wildcarded)
785
 * @return false on error.
786
 */
787
static int
788
anchor_read_bind_file_wild(struct val_anchors* anchors, sldns_buffer* buffer,
789
  const char* pat)
790
0
{
791
0
#ifdef HAVE_GLOB
792
0
  glob_t g;
793
0
  size_t i;
794
0
  int r, flags;
795
0
  if(!strchr(pat, '*') && !strchr(pat, '?') && !strchr(pat, '[') && 
796
0
    !strchr(pat, '{') && !strchr(pat, '~')) {
797
0
    return anchor_read_bind_file(anchors, buffer, pat);
798
0
  }
799
0
  verbose(VERB_QUERY, "wildcard found, processing %s", pat);
800
0
  flags = 0 
801
0
#ifdef GLOB_ERR
802
0
    | GLOB_ERR
803
0
#endif
804
0
#ifdef GLOB_NOSORT
805
0
    | GLOB_NOSORT
806
0
#endif
807
0
#ifdef GLOB_BRACE
808
0
    | GLOB_BRACE
809
0
#endif
810
0
#ifdef GLOB_TILDE
811
0
    | GLOB_TILDE
812
0
#endif
813
0
  ;
814
0
  memset(&g, 0, sizeof(g));
815
0
  r = glob(pat, flags, NULL, &g);
816
0
  if(r) {
817
    /* some error */
818
0
    if(r == GLOB_NOMATCH) {
819
0
      verbose(VERB_QUERY, "trusted-keys-file: "
820
0
        "no matches for %s", pat);
821
0
      return 1;
822
0
    } else if(r == GLOB_NOSPACE) {
823
0
      log_err("wildcard trusted-keys-file %s: "
824
0
        "pattern out of memory", pat);
825
0
    } else if(r == GLOB_ABORTED) {
826
0
      log_err("wildcard trusted-keys-file %s: expansion "
827
0
        "aborted (%s)", pat, strerror(errno));
828
0
    } else {
829
0
      log_err("wildcard trusted-keys-file %s: expansion "
830
0
        "failed (%s)", pat, strerror(errno));
831
0
    }
832
    /* ignore globs that yield no files */
833
0
    return 1; 
834
0
  }
835
  /* process files found, if any */
836
0
  for(i=0; i<(size_t)g.gl_pathc; i++) {
837
0
    if(!anchor_read_bind_file(anchors, buffer, g.gl_pathv[i])) {
838
0
      log_err("error reading wildcard "
839
0
        "trusted-keys-file: %s", g.gl_pathv[i]);
840
0
      globfree(&g);
841
0
      return 0;
842
0
    }
843
0
  }
844
0
  globfree(&g);
845
0
  return 1;
846
#else /* not HAVE_GLOB */
847
  return anchor_read_bind_file(anchors, buffer, pat);
848
#endif /* HAVE_GLOB */
849
0
}
850
851
/** 
852
 * Assemble an rrset structure for the type 
853
 * @param ta: trust anchor.
854
 * @param num: number of items to fetch from list.
855
 * @param type: fetch only items of this type.
856
 * @return rrset or NULL on error.
857
 */
858
static struct ub_packed_rrset_key*
859
assemble_it(struct trust_anchor* ta, size_t num, uint16_t type)
860
0
{
861
0
  struct ub_packed_rrset_key* pkey = (struct ub_packed_rrset_key*)
862
0
    malloc(sizeof(*pkey));
863
0
  struct packed_rrset_data* pd;
864
0
  struct ta_key* tk;
865
0
  size_t i;
866
0
  if(!pkey)
867
0
    return NULL;
868
0
  memset(pkey, 0, sizeof(*pkey));
869
0
  pkey->rk.dname = memdup(ta->name, ta->namelen);
870
0
  if(!pkey->rk.dname) {
871
0
    free(pkey);
872
0
    return NULL;
873
0
  }
874
875
0
  pkey->rk.dname_len = ta->namelen;
876
0
  pkey->rk.type = htons(type);
877
0
  pkey->rk.rrset_class = htons(ta->dclass);
878
  /* The rrset is build in an uncompressed way. This means it
879
   * cannot be copied in the normal way. */
880
0
  pd = (struct packed_rrset_data*)malloc(sizeof(*pd));
881
0
  if(!pd) {
882
0
    free(pkey->rk.dname);
883
0
    free(pkey);
884
0
    return NULL;
885
0
  }
886
0
  memset(pd, 0, sizeof(*pd));
887
0
  pd->count = num;
888
0
  pd->trust = rrset_trust_ultimate;
889
0
  pd->rr_len = (size_t*)reallocarray(NULL, num, sizeof(size_t));
890
0
  if(!pd->rr_len) {
891
0
    free(pd);
892
0
    free(pkey->rk.dname);
893
0
    free(pkey);
894
0
    return NULL;
895
0
  }
896
0
  pd->rr_ttl = (time_t*)reallocarray(NULL, num, sizeof(time_t));
897
0
  if(!pd->rr_ttl) {
898
0
    free(pd->rr_len);
899
0
    free(pd);
900
0
    free(pkey->rk.dname);
901
0
    free(pkey);
902
0
    return NULL;
903
0
  }
904
0
  pd->rr_data = (uint8_t**)reallocarray(NULL, num, sizeof(uint8_t*));
905
0
  if(!pd->rr_data) {
906
0
    free(pd->rr_ttl);
907
0
    free(pd->rr_len);
908
0
    free(pd);
909
0
    free(pkey->rk.dname);
910
0
    free(pkey);
911
0
    return NULL;
912
0
  }
913
  /* fill in rrs */
914
0
  i=0;
915
0
  for(tk = ta->keylist; tk; tk = tk->next) {
916
0
    if(tk->type != type)
917
0
      continue;
918
0
    pd->rr_len[i] = tk->len;
919
    /* reuse data ptr to allocation in talist */
920
0
    pd->rr_data[i] = tk->data;
921
0
    pd->rr_ttl[i] = 0;
922
0
    i++;
923
0
  }
924
0
  pkey->entry.data = (void*)pd;
925
0
  return pkey;
926
0
}
927
928
/**
929
 * Assemble structures for the trust DS and DNSKEY rrsets.
930
 * @param ta: trust anchor
931
 * @return: false on error.
932
 */
933
static int
934
anchors_assemble(struct trust_anchor* ta)
935
0
{
936
0
  if(ta->numDS > 0) {
937
0
    ta->ds_rrset = assemble_it(ta, ta->numDS, LDNS_RR_TYPE_DS);
938
0
    if(!ta->ds_rrset)
939
0
      return 0;
940
0
  }
941
0
  if(ta->numDNSKEY > 0) {
942
0
    ta->dnskey_rrset = assemble_it(ta, ta->numDNSKEY,
943
0
      LDNS_RR_TYPE_DNSKEY);
944
0
    if(!ta->dnskey_rrset)
945
0
      return 0;
946
0
  }
947
0
  return 1;
948
0
}
949
950
/**
951
 * Check DS algos for support, warn if not.
952
 * @param ta: trust anchor
953
 * @return number of DS anchors with unsupported algorithms.
954
 */
955
static size_t
956
anchors_ds_unsupported(struct trust_anchor* ta)
957
0
{
958
0
  size_t i, num = 0;
959
0
  for(i=0; i<ta->numDS; i++) {
960
0
    if(!ds_digest_algo_is_supported(ta->ds_rrset, i) || 
961
0
      !ds_key_algo_is_supported(ta->ds_rrset, i))
962
0
      num++;
963
0
  }
964
0
  return num;
965
0
}
966
967
/**
968
 * Check DNSKEY algos for support, warn if not.
969
 * @param ta: trust anchor
970
 * @return number of DNSKEY anchors with unsupported algorithms.
971
 */
972
static size_t
973
anchors_dnskey_unsupported(struct trust_anchor* ta)
974
0
{
975
0
  size_t i, num = 0;
976
0
  for(i=0; i<ta->numDNSKEY; i++) {
977
0
    if(!dnskey_algo_is_supported(ta->dnskey_rrset, i) ||
978
0
      !dnskey_size_is_supported(ta->dnskey_rrset, i))
979
0
      num++;
980
0
  }
981
0
  return num;
982
0
}
983
984
/**
985
 * Assemble the rrsets in the anchors, ready for use by validator.
986
 * @param anchors: trust anchor storage.
987
 * @return: false on error.
988
 */
989
static int
990
anchors_assemble_rrsets(struct val_anchors* anchors)
991
0
{
992
0
  struct trust_anchor* ta;
993
0
  struct trust_anchor* next;
994
0
  size_t nods, nokey;
995
0
  lock_basic_lock(&anchors->lock);
996
0
  ta=(struct trust_anchor*)rbtree_first(anchors->tree);
997
0
  while((rbnode_type*)ta != RBTREE_NULL) {
998
0
    next = (struct trust_anchor*)rbtree_next(&ta->node);
999
0
    lock_basic_lock(&ta->lock);
1000
0
    if(ta->autr || (ta->numDS == 0 && ta->numDNSKEY == 0)) {
1001
0
      lock_basic_unlock(&ta->lock);
1002
0
      ta = next; /* skip */
1003
0
      continue;
1004
0
    }
1005
0
    if(!anchors_assemble(ta)) {
1006
0
      log_err("out of memory");
1007
0
      lock_basic_unlock(&ta->lock);
1008
0
      lock_basic_unlock(&anchors->lock);
1009
0
      return 0;
1010
0
    }
1011
0
    nods = anchors_ds_unsupported(ta);
1012
0
    nokey = anchors_dnskey_unsupported(ta);
1013
0
    if(nods) {
1014
0
      log_nametypeclass(NO_VERBOSE, "warning: unsupported "
1015
0
        "algorithm for trust anchor", 
1016
0
        ta->name, LDNS_RR_TYPE_DS, ta->dclass);
1017
0
    }
1018
0
    if(nokey) {
1019
0
      log_nametypeclass(NO_VERBOSE, "warning: unsupported "
1020
0
        "algorithm for trust anchor", 
1021
0
        ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
1022
0
    }
1023
0
    if(nods == ta->numDS && nokey == ta->numDNSKEY) {
1024
0
      char b[LDNS_MAX_DOMAINLEN];
1025
0
      dname_str(ta->name, b);
1026
0
      log_warn("trust anchor %s has no supported algorithms,"
1027
0
        " the anchor is ignored (check if you need to"
1028
0
        " upgrade unbound and "
1029
#ifdef HAVE_LIBRESSL
1030
        "libressl"
1031
#else
1032
0
        "openssl"
1033
0
#endif
1034
0
        ")", b);
1035
0
      (void)rbtree_delete(anchors->tree, &ta->node);
1036
0
      lock_basic_unlock(&ta->lock);
1037
0
      anchors_delfunc(&ta->node, NULL);
1038
0
      ta = next;
1039
0
      continue;
1040
0
    }
1041
0
    lock_basic_unlock(&ta->lock);
1042
0
    ta = next;
1043
0
  }
1044
0
  lock_basic_unlock(&anchors->lock);
1045
0
  return 1;
1046
0
}
1047
1048
int 
1049
anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
1050
0
{
1051
0
  struct config_strlist* f;
1052
0
  const char** zstr;
1053
0
  char* nm;
1054
0
  sldns_buffer* parsebuf = sldns_buffer_new(65535);
1055
0
  if(!parsebuf) {
1056
0
    log_err("malloc error in anchors_apply_cfg.");
1057
0
    return 0;
1058
0
  }
1059
0
  if(cfg->insecure_lan_zones) {
1060
0
    for(zstr = as112_zones; *zstr; zstr++) {
1061
0
      if(!anchor_insert_insecure(anchors, *zstr)) {
1062
0
        log_err("error in insecure-lan-zones: %s", *zstr);
1063
0
        sldns_buffer_free(parsebuf);
1064
0
        return 0;
1065
0
      }
1066
0
    }
1067
0
  }
1068
0
  for(f = cfg->domain_insecure; f; f = f->next) {
1069
0
    if(!f->str || f->str[0] == 0) /* empty "" */
1070
0
      continue;
1071
0
    if(!anchor_insert_insecure(anchors, f->str)) {
1072
0
      log_err("error in domain-insecure: %s", f->str);
1073
0
      sldns_buffer_free(parsebuf);
1074
0
      return 0;
1075
0
    }
1076
0
  }
1077
0
  for(f = cfg->trust_anchor_file_list; f; f = f->next) {
1078
0
    if(!f->str || f->str[0] == 0) /* empty "" */
1079
0
      continue;
1080
0
    nm = f->str;
1081
0
    if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1082
0
      cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1083
0
      nm += strlen(cfg->chrootdir);
1084
0
    if(!anchor_read_file(anchors, parsebuf, nm, 0)) {
1085
0
      log_err("error reading trust-anchor-file: %s", f->str);
1086
0
      sldns_buffer_free(parsebuf);
1087
0
      return 0;
1088
0
    }
1089
0
  }
1090
0
  for(f = cfg->trusted_keys_file_list; f; f = f->next) {
1091
0
    if(!f->str || f->str[0] == 0) /* empty "" */
1092
0
      continue;
1093
0
    nm = f->str;
1094
0
    if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1095
0
      cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1096
0
      nm += strlen(cfg->chrootdir);
1097
0
    if(!anchor_read_bind_file_wild(anchors, parsebuf, nm)) {
1098
0
      log_err("error reading trusted-keys-file: %s", f->str);
1099
0
      sldns_buffer_free(parsebuf);
1100
0
      return 0;
1101
0
    }
1102
0
  }
1103
0
  for(f = cfg->trust_anchor_list; f; f = f->next) {
1104
0
    if(!f->str || f->str[0] == 0) /* empty "" */
1105
0
      continue;
1106
0
    if(!anchor_store_str(anchors, parsebuf, f->str)) {
1107
0
      log_err("error in trust-anchor: \"%s\"", f->str);
1108
0
      sldns_buffer_free(parsebuf);
1109
0
      return 0;
1110
0
    }
1111
0
  }
1112
  /* do autr last, so that it sees what anchors are filled by other
1113
   * means can can print errors about double config for the name */
1114
0
  for(f = cfg->auto_trust_anchor_file_list; f; f = f->next) {
1115
0
    if(!f->str || f->str[0] == 0) /* empty "" */
1116
0
      continue;
1117
0
    nm = f->str;
1118
0
    if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
1119
0
      cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
1120
0
      nm += strlen(cfg->chrootdir);
1121
0
    if(!autr_read_file(anchors, nm)) {
1122
0
      log_err("error reading auto-trust-anchor-file: %s", 
1123
0
        f->str);
1124
0
      sldns_buffer_free(parsebuf);
1125
0
      return 0;
1126
0
    }
1127
0
  }
1128
  /* first assemble, since it may delete useless anchors */
1129
0
  anchors_assemble_rrsets(anchors);
1130
0
  init_parents(anchors);
1131
0
  sldns_buffer_free(parsebuf);
1132
0
  if(verbosity >= VERB_ALGO) autr_debug_print(anchors);
1133
0
  return 1;
1134
0
}
1135
1136
struct trust_anchor* 
1137
anchors_lookup(struct val_anchors* anchors,
1138
        uint8_t* qname, size_t qname_len, uint16_t qclass)
1139
0
{
1140
0
  struct trust_anchor key;
1141
0
  struct trust_anchor* result;
1142
0
  rbnode_type* res = NULL;
1143
0
  key.node.key = &key;
1144
0
  key.name = qname;
1145
0
  key.namelabs = dname_count_labels(qname);
1146
0
  key.namelen = qname_len;
1147
0
  key.dclass = qclass;
1148
0
  lock_basic_lock(&anchors->lock);
1149
0
  if(rbtree_find_less_equal(anchors->tree, &key, &res)) {
1150
    /* exact */
1151
0
    result = (struct trust_anchor*)res;
1152
0
  } else {
1153
    /* smaller element (or no element) */
1154
0
    int m;
1155
0
    result = (struct trust_anchor*)res;
1156
0
    if(!result || result->dclass != qclass) {
1157
0
      lock_basic_unlock(&anchors->lock);
1158
0
      return NULL;
1159
0
    }
1160
    /* count number of labels matched */
1161
0
    (void)dname_lab_cmp(result->name, result->namelabs, key.name,
1162
0
      key.namelabs, &m);
1163
0
    while(result) { /* go up until qname is subdomain of stub */
1164
0
      if(result->namelabs <= m)
1165
0
        break;
1166
0
      result = result->parent;
1167
0
    }
1168
0
  }
1169
0
  if(result) {
1170
0
    lock_basic_lock(&result->lock);
1171
0
  }
1172
0
  lock_basic_unlock(&anchors->lock);
1173
0
  return result;
1174
0
}
1175
1176
/** Get memory usage of assembled key rrset */
1177
static size_t
1178
assembled_rrset_get_mem(struct ub_packed_rrset_key* pkey)
1179
0
{
1180
0
  size_t s;
1181
0
  if(!pkey)
1182
0
    return 0;
1183
0
  s = sizeof(*pkey) + pkey->rk.dname_len;
1184
0
  if(pkey->entry.data) {
1185
0
    struct packed_rrset_data* pd = (struct packed_rrset_data*)
1186
0
      pkey->entry.data;
1187
0
    s += sizeof(*pd) + pd->count * (sizeof(size_t)+sizeof(time_t)+
1188
0
      sizeof(uint8_t*));
1189
0
  }
1190
0
  return s;
1191
0
}
1192
1193
size_t 
1194
anchors_get_mem(struct val_anchors* anchors)
1195
0
{
1196
0
  struct trust_anchor *ta;
1197
0
  struct ta_key *k;
1198
0
  size_t s;
1199
0
  if(!anchors) return 0;
1200
0
  s = sizeof(*anchors);
1201
0
  lock_basic_lock(&anchors->lock);
1202
0
  RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) {
1203
0
    lock_basic_lock(&ta->lock);
1204
0
    s += sizeof(*ta) + ta->namelen;
1205
    /* keys and so on */
1206
0
    for(k = ta->keylist; k; k = k->next) {
1207
0
      s += sizeof(*k) + k->len;
1208
0
    }
1209
0
    s += assembled_rrset_get_mem(ta->ds_rrset);
1210
0
    s += assembled_rrset_get_mem(ta->dnskey_rrset);
1211
0
    if(ta->autr) {
1212
0
      struct autr_ta* p;
1213
0
      s += sizeof(*ta->autr);
1214
0
      if(ta->autr->file)
1215
0
        s += strlen(ta->autr->file);
1216
0
      for(p = ta->autr->keys; p; p=p->next) {
1217
0
        s += sizeof(*p) + p->rr_len;
1218
0
      }
1219
0
    }
1220
0
    lock_basic_unlock(&ta->lock);
1221
0
  }
1222
0
  lock_basic_unlock(&anchors->lock);
1223
0
  return s;
1224
0
}
1225
1226
int
1227
anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm)
1228
0
{
1229
0
  struct trust_anchor key;
1230
0
  key.node.key = &key;
1231
0
  key.name = nm;
1232
0
  key.namelabs = dname_count_size_labels(nm, &key.namelen);
1233
0
  key.dclass = c;
1234
0
  lock_basic_lock(&anchors->lock);
1235
0
  if(rbtree_search(anchors->tree, &key)) {
1236
0
    lock_basic_unlock(&anchors->lock);
1237
    /* nothing to do, already an anchor or insecure point */
1238
0
    return 1;
1239
0
  }
1240
0
  if(!anchor_new_ta(anchors, nm, key.namelabs, key.namelen, c, 0)) {
1241
0
    log_err("out of memory");
1242
0
    lock_basic_unlock(&anchors->lock);
1243
0
    return 0;
1244
0
  }
1245
  /* no other contents in new ta, because it is insecure point */
1246
0
  anchors_init_parents_locked(anchors);
1247
0
  lock_basic_unlock(&anchors->lock);
1248
0
  return 1;
1249
0
}
1250
1251
void
1252
anchors_delete_insecure(struct val_anchors* anchors, uint16_t c,
1253
        uint8_t* nm)
1254
0
{
1255
0
  struct trust_anchor key;
1256
0
  struct trust_anchor* ta;
1257
0
  key.node.key = &key;
1258
0
  key.name = nm;
1259
0
  key.namelabs = dname_count_size_labels(nm, &key.namelen);
1260
0
  key.dclass = c;
1261
0
  lock_basic_lock(&anchors->lock);
1262
0
  if(!(ta=(struct trust_anchor*)rbtree_search(anchors->tree, &key))) {
1263
0
    lock_basic_unlock(&anchors->lock);
1264
    /* nothing there */
1265
0
    return;
1266
0
  }
1267
  /* lock it to drive away other threads that use it */
1268
0
  lock_basic_lock(&ta->lock);
1269
  /* see if its really an insecure point */
1270
0
  if(ta->keylist || ta->autr || ta->numDS || ta->numDNSKEY) {
1271
0
    lock_basic_unlock(&anchors->lock);
1272
0
    lock_basic_unlock(&ta->lock);
1273
    /* its not an insecure point, do not remove it */
1274
0
    return;
1275
0
  }
1276
1277
  /* remove from tree */
1278
0
  (void)rbtree_delete(anchors->tree, &ta->node);
1279
0
  anchors_init_parents_locked(anchors);
1280
0
  lock_basic_unlock(&anchors->lock);
1281
1282
  /* actual free of data */
1283
0
  lock_basic_unlock(&ta->lock);
1284
0
  anchors_delfunc(&ta->node, NULL);
1285
0
}
1286
1287
/** compare two keytags, return -1, 0 or 1 */
1288
static int
1289
keytag_compare(const void* x, const void* y)
1290
0
{
1291
0
  if(*(uint16_t*)x == *(uint16_t*)y)
1292
0
    return 0;
1293
0
  if(*(uint16_t*)x > *(uint16_t*)y)
1294
0
    return 1;
1295
0
  return -1;
1296
0
}
1297
1298
size_t
1299
anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num)
1300
0
{
1301
0
  size_t i, ret = 0;
1302
0
  if(ta->numDS == 0 && ta->numDNSKEY == 0)
1303
0
    return 0; /* insecure point */
1304
0
  if(ta->numDS != 0 && ta->ds_rrset) {
1305
0
    struct packed_rrset_data* d=(struct packed_rrset_data*)
1306
0
      ta->ds_rrset->entry.data;
1307
0
    for(i=0; i<d->count; i++) {
1308
0
      if(ret == num) continue;
1309
0
      list[ret++] = ds_get_keytag(ta->ds_rrset, i);
1310
0
    }
1311
0
  }
1312
0
  if(ta->numDNSKEY != 0 && ta->dnskey_rrset) {
1313
0
    struct packed_rrset_data* d=(struct packed_rrset_data*)
1314
0
      ta->dnskey_rrset->entry.data;
1315
0
    for(i=0; i<d->count; i++) {
1316
0
      if(ret == num) continue;
1317
0
      list[ret++] = dnskey_calc_keytag(ta->dnskey_rrset, i);
1318
0
    }
1319
0
  }
1320
0
  qsort(list, ret, sizeof(*list), keytag_compare);
1321
0
  return ret;
1322
0
}
1323
1324
int
1325
anchor_has_keytag(struct val_anchors* anchors, uint8_t* name, int namelabs,
1326
  size_t namelen, uint16_t dclass, uint16_t keytag)
1327
0
{
1328
0
  uint16_t* taglist;
1329
0
  uint16_t* tl;
1330
0
  size_t numtag, i;
1331
0
  struct trust_anchor* anchor = anchor_find(anchors,
1332
0
    name, namelabs, namelen, dclass);
1333
0
  if(!anchor)
1334
0
    return 0;
1335
0
  if(!anchor->numDS && !anchor->numDNSKEY) {
1336
0
    lock_basic_unlock(&anchor->lock);
1337
0
    return 0;
1338
0
  }
1339
1340
0
  taglist = calloc(anchor->numDS + anchor->numDNSKEY, sizeof(*taglist));
1341
0
  if(!taglist) {
1342
0
    lock_basic_unlock(&anchor->lock);
1343
0
    return 0;
1344
0
  }
1345
1346
0
  numtag = anchor_list_keytags(anchor, taglist,
1347
0
    anchor->numDS+anchor->numDNSKEY);
1348
0
  lock_basic_unlock(&anchor->lock);
1349
0
  if(!numtag) {
1350
0
    free(taglist);
1351
0
    return 0;
1352
0
  }
1353
0
  tl = taglist;
1354
0
  for(i=0; i<numtag; i++) {
1355
0
    if(*tl == keytag) {
1356
0
      free(taglist);
1357
0
      return 1;
1358
0
    }
1359
0
    tl++;
1360
0
  }
1361
0
  free(taglist);
1362
0
  return 0;
1363
0
}
1364
1365
struct trust_anchor*
1366
anchors_find_any_noninsecure(struct val_anchors* anchors)
1367
0
{
1368
0
  struct trust_anchor* ta, *next;
1369
0
  lock_basic_lock(&anchors->lock);
1370
0
  ta=(struct trust_anchor*)rbtree_first(anchors->tree);
1371
0
  while((rbnode_type*)ta != RBTREE_NULL) {
1372
0
    next = (struct trust_anchor*)rbtree_next(&ta->node);
1373
0
    lock_basic_lock(&ta->lock);
1374
0
    if(ta->numDS != 0 || ta->numDNSKEY != 0) {
1375
      /* not an insecurepoint */
1376
0
      lock_basic_unlock(&anchors->lock);
1377
0
      return ta;
1378
0
    }
1379
0
    lock_basic_unlock(&ta->lock);
1380
0
    ta = next;
1381
0
  }
1382
0
  lock_basic_unlock(&anchors->lock);
1383
0
  return NULL;
1384
0
}
1385
1386
void
1387
anchors_swap_tree(struct val_anchors* anchors, struct val_anchors* data)
1388
0
{
1389
0
  rbtree_type* oldtree;
1390
0
  rbtree_type oldprobe;
1391
1392
0
  if(!anchors || !data)
1393
0
    return; /* If anchors is NULL, there is no validation. */
1394
1395
0
  oldtree = anchors->tree;
1396
0
  oldprobe = anchors->autr->probe;
1397
1398
0
  anchors->tree = data->tree;
1399
0
  anchors->autr->probe = data->autr->probe;
1400
1401
0
  data->tree = oldtree;
1402
0
  data->autr->probe = oldprobe;
1403
0
}