Coverage Report

Created: 2026-01-10 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/keytable.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stdbool.h>
17
18
#include <isc/mem.h>
19
#include <isc/refcount.h>
20
#include <isc/result.h>
21
#include <isc/rwlock.h>
22
#include <isc/string.h>
23
#include <isc/util.h>
24
25
#include <dns/dnssec.h>
26
#include <dns/fixedname.h>
27
#include <dns/keytable.h>
28
#include <dns/qp.h>
29
#include <dns/rdata.h>
30
#include <dns/rdatalist.h>
31
#include <dns/rdataset.h>
32
#include <dns/rdatastruct.h>
33
#include <dns/view.h>
34
35
0
#define KEYTABLE_MAGIC     ISC_MAGIC('K', 'T', 'b', 'l')
36
#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
37
38
0
#define KEYNODE_MAGIC   ISC_MAGIC('K', 'N', 'o', 'd')
39
#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
40
41
struct dns_keytable {
42
  unsigned int magic;
43
  isc_mem_t *mctx;
44
  isc_refcount_t references;
45
  isc_rwlock_t rwlock;
46
  dns_qpmulti_t *table;
47
};
48
49
struct dns_keynode {
50
  unsigned int magic;
51
  isc_mem_t *mctx;
52
  isc_refcount_t references;
53
  isc_rwlock_t rwlock;
54
  dns_name_t name;
55
  dns_rdatalist_t *dslist;
56
  dns_rdataset_t dsset;
57
  bool managed;
58
  bool initial;
59
};
60
61
static dns_keynode_t *
62
new_keynode(const dns_name_t *name, dns_rdata_ds_t *ds,
63
      dns_keytable_t *keytable, bool managed, bool initial);
64
65
/* QP trie methods */
66
static void
67
qp_attach(void *uctx, void *pval, uint32_t ival);
68
static void
69
qp_detach(void *uctx, void *pval, uint32_t ival);
70
static size_t
71
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
72
static void
73
qp_triename(void *uctx, char *buf, size_t size);
74
75
static dns_qpmethods_t qpmethods = {
76
  qp_attach,
77
  qp_detach,
78
  qp_makekey,
79
  qp_triename,
80
};
81
82
/* rdataset methods */
83
static void
84
keynode_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
85
static isc_result_t
86
keynode_first(dns_rdataset_t *rdataset);
87
static isc_result_t
88
keynode_next(dns_rdataset_t *rdataset);
89
static void
90
keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
91
static void
92
keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
93
94
static dns_rdatasetmethods_t methods = {
95
  .disassociate = keynode_disassociate,
96
  .first = keynode_first,
97
  .next = keynode_next,
98
  .current = keynode_current,
99
  .clone = keynode_clone,
100
};
101
102
static void
103
0
destroy_keynode(dns_keynode_t *knode) {
104
0
  isc_rwlock_destroy(&knode->rwlock);
105
0
  if (knode->dslist != NULL) {
106
0
    ISC_LIST_FOREACH(knode->dslist->rdata, rdata, link) {
107
0
      ISC_LIST_UNLINK(knode->dslist->rdata, rdata, link);
108
0
      isc_mem_put(knode->mctx, rdata->data,
109
0
            DNS_DS_BUFFERSIZE);
110
0
      isc_mem_put(knode->mctx, rdata, sizeof(*rdata));
111
0
    }
112
113
0
    isc_mem_put(knode->mctx, knode->dslist, sizeof(*knode->dslist));
114
0
  }
115
116
0
  dns_name_free(&knode->name, knode->mctx);
117
0
  isc_mem_putanddetach(&knode->mctx, knode, sizeof(dns_keynode_t));
118
0
}
119
120
0
ISC_REFCOUNT_IMPL(dns_keynode, destroy_keynode);
Unexecuted instantiation: dns_keynode_ref
Unexecuted instantiation: dns_keynode_unref
Unexecuted instantiation: dns_keynode_detach
121
0
122
0
void
123
0
dns_keytable_create(dns_view_t *view, dns_keytable_t **keytablep) {
124
0
  dns_keytable_t *keytable = NULL;
125
126
  /*
127
   * Create a keytable.
128
   */
129
130
0
  REQUIRE(keytablep != NULL && *keytablep == NULL);
131
132
0
  keytable = isc_mem_get(view->mctx, sizeof(*keytable));
133
0
  *keytable = (dns_keytable_t){
134
0
    .magic = KEYTABLE_MAGIC,
135
0
  };
136
137
0
  isc_mem_attach(view->mctx, &keytable->mctx);
138
0
  dns_qpmulti_create(view->mctx, &qpmethods, view, &keytable->table);
139
0
  isc_refcount_init(&keytable->references, 1);
140
0
  *keytablep = keytable;
141
0
}
142
143
static void
144
0
destroy_keytable(dns_keytable_t *keytable) {
145
0
  dns_qpread_t qpr;
146
0
  dns_qpiter_t iter;
147
0
  void *pval = NULL;
148
149
0
  keytable->magic = 0;
150
151
0
  dns_qpmulti_query(keytable->table, &qpr);
152
0
  dns_qpiter_init(&qpr, &iter);
153
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
154
0
    dns_keynode_t *n = pval;
155
0
    dns_keynode_detach(&n);
156
0
  }
157
0
  dns_qpread_destroy(keytable->table, &qpr);
158
159
0
  dns_qpmulti_destroy(&keytable->table);
160
161
0
  isc_mem_putanddetach(&keytable->mctx, keytable, sizeof(*keytable));
162
0
}
163
164
0
ISC_REFCOUNT_IMPL(dns_keytable, destroy_keytable);
Unexecuted instantiation: dns_keytable_ref
Unexecuted instantiation: dns_keytable_unref
Unexecuted instantiation: dns_keytable_detach
165
0
166
0
static void
167
0
add_ds(dns_keynode_t *knode, dns_rdata_ds_t *ds, isc_mem_t *mctx) {
168
0
  isc_result_t result;
169
0
  dns_rdata_t *dsrdata = NULL;
170
0
  void *data = NULL;
171
0
  bool exists = false;
172
0
  isc_buffer_t b;
173
174
0
  dsrdata = isc_mem_get(mctx, sizeof(*dsrdata));
175
0
  dns_rdata_init(dsrdata);
176
177
0
  data = isc_mem_get(mctx, DNS_DS_BUFFERSIZE);
178
0
  isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
179
180
0
  result = dns_rdata_fromstruct(dsrdata, dns_rdataclass_in,
181
0
              dns_rdatatype_ds, ds, &b);
182
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
183
184
0
  RWLOCK(&knode->rwlock, isc_rwlocktype_write);
185
186
0
  if (knode->dslist == NULL) {
187
0
    knode->dslist = isc_mem_get(mctx, sizeof(*knode->dslist));
188
0
    dns_rdatalist_init(knode->dslist);
189
0
    knode->dslist->rdclass = dns_rdataclass_in;
190
0
    knode->dslist->type = dns_rdatatype_ds;
191
192
0
    INSIST(knode->dsset.methods == NULL);
193
0
    knode->dsset.methods = &methods;
194
0
    knode->dsset.rdclass = knode->dslist->rdclass;
195
0
    knode->dsset.type = knode->dslist->type;
196
0
    knode->dsset.covers = knode->dslist->covers;
197
0
    knode->dsset.ttl = knode->dslist->ttl;
198
0
    knode->dsset.keytable.node = knode;
199
0
    knode->dsset.keytable.iter = NULL;
200
0
    knode->dsset.trust = dns_trust_ultimate;
201
0
  }
202
203
0
  ISC_LIST_FOREACH(knode->dslist->rdata, rdata, link) {
204
0
    if (dns_rdata_compare(rdata, dsrdata) == 0) {
205
0
      exists = true;
206
0
      break;
207
0
    }
208
0
  }
209
210
0
  if (exists) {
211
0
    isc_mem_put(mctx, dsrdata->data, DNS_DS_BUFFERSIZE);
212
0
    isc_mem_put(mctx, dsrdata, sizeof(*dsrdata));
213
0
  } else {
214
0
    ISC_LIST_APPEND(knode->dslist->rdata, dsrdata, link);
215
0
  }
216
217
0
  RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
218
0
}
219
220
static isc_result_t
221
delete_ds(dns_qp_t *qp, dns_keytable_t *keytable, dns_keynode_t *knode,
222
0
    dns_rdata_ds_t *ds) {
223
0
  isc_result_t result;
224
0
  dns_rdata_t dsrdata = DNS_RDATA_INIT;
225
0
  dns_keynode_t *newnode = NULL;
226
0
  unsigned char data[DNS_DS_BUFFERSIZE];
227
0
  bool found = false;
228
0
  void *pval = NULL;
229
0
  isc_buffer_t b;
230
231
0
  RWLOCK(&knode->rwlock, isc_rwlocktype_read);
232
0
  if (knode->dslist == NULL) {
233
0
    RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
234
0
    return ISC_R_SUCCESS;
235
0
  }
236
237
0
  isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
238
239
0
  result = dns_rdata_fromstruct(&dsrdata, dns_rdataclass_in,
240
0
              dns_rdatatype_ds, ds, &b);
241
0
  if (result != ISC_R_SUCCESS) {
242
0
    RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
243
0
    return result;
244
0
  }
245
246
0
  ISC_LIST_FOREACH(knode->dslist->rdata, rdata, link) {
247
0
    if (dns_rdata_compare(rdata, &dsrdata) == 0) {
248
0
      found = true;
249
0
      break;
250
0
    }
251
0
  }
252
253
0
  if (!found) {
254
0
    RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
255
    /*
256
     * The keyname must have matched or we wouldn't be here,
257
     * so we use DNS_R_PARTIALMATCH instead of ISC_R_NOTFOUND.
258
     */
259
0
    return DNS_R_PARTIALMATCH;
260
0
  }
261
262
  /*
263
   * Replace knode with a new instance without the DS.
264
   */
265
0
  newnode = new_keynode(&knode->name, NULL, keytable, knode->managed,
266
0
            knode->initial);
267
0
  ISC_LIST_FOREACH(knode->dslist->rdata, rdata, link) {
268
0
    if (dns_rdata_compare(rdata, &dsrdata) != 0) {
269
0
      dns_rdata_ds_t ds0;
270
0
      result = dns_rdata_tostruct(rdata, &ds0, NULL);
271
0
      RUNTIME_CHECK(result == ISC_R_SUCCESS);
272
0
      add_ds(newnode, &ds0, keytable->mctx);
273
0
    }
274
0
  }
275
276
0
  result = dns_qp_deletename(qp, &knode->name, DNS_DBNAMESPACE_NORMAL,
277
0
           &pval, NULL);
278
0
  INSIST(result == ISC_R_SUCCESS);
279
0
  INSIST(pval == knode);
280
281
0
  result = dns_qp_insert(qp, newnode, 0);
282
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
283
284
0
  RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
285
286
0
  dns_keynode_detach(&knode);
287
0
  return ISC_R_SUCCESS;
288
0
}
289
290
/*%
291
 * Create a keynode for "ds" (or a null key node if "ds" is NULL), set
292
 * "managed" and "initial" as requested and attach the keynode to
293
 * to "node" in "keytable".
294
 */
295
static dns_keynode_t *
296
new_keynode(const dns_name_t *name, dns_rdata_ds_t *ds,
297
0
      dns_keytable_t *keytable, bool managed, bool initial) {
298
0
  dns_keynode_t *knode = NULL;
299
300
0
  REQUIRE(VALID_KEYTABLE(keytable));
301
0
  REQUIRE(!initial || managed);
302
303
0
  knode = isc_mem_get(keytable->mctx, sizeof(dns_keynode_t));
304
0
  *knode = (dns_keynode_t){ .name = DNS_NAME_INITEMPTY,
305
0
          .magic = KEYNODE_MAGIC };
306
307
0
  dns_rdataset_init(&knode->dsset);
308
0
  isc_refcount_init(&knode->references, 1);
309
0
  isc_rwlock_init(&knode->rwlock);
310
311
0
  dns_name_dup(name, keytable->mctx, &knode->name);
312
313
  /*
314
   * If a DS was supplied, initialize an rdatalist.
315
   */
316
0
  if (ds != NULL) {
317
0
    add_ds(knode, ds, keytable->mctx);
318
0
  }
319
320
0
  isc_mem_attach(keytable->mctx, &knode->mctx);
321
0
  knode->managed = managed;
322
0
  knode->initial = initial;
323
324
0
  return knode;
325
0
}
326
327
/*%
328
 * Add key trust anchor "ds" at "keyname" in "keytable".  If an anchor
329
 * already exists at the requested name does not contain "ds", update it.
330
 * If "ds" is NULL, add a null key to indicate that "keyname" should be
331
 * treated as a secure domain without supplying key data which would allow
332
 * the domain to be validated.
333
 */
334
static isc_result_t
335
insert(dns_keytable_t *keytable, bool managed, bool initial,
336
       const dns_name_t *keyname, dns_rdata_ds_t *ds,
337
0
       dns_keytable_callback_t callback, void *callback_arg) {
338
0
  isc_result_t result;
339
0
  dns_keynode_t *newnode = NULL;
340
0
  dns_qp_t *qp = NULL;
341
0
  void *pval = NULL;
342
343
0
  REQUIRE(VALID_KEYTABLE(keytable));
344
345
0
  dns_qpmulti_write(keytable->table, &qp);
346
347
0
  result = dns_qp_getname(qp, keyname, DNS_DBNAMESPACE_NORMAL, &pval,
348
0
        NULL);
349
0
  if (result != ISC_R_SUCCESS) {
350
    /*
351
     * There was no match for "keyname" in "keytable" yet, so one
352
     * was created.  Create a new key node for the supplied
353
     * trust anchor (or a null key node if "ds" is NULL)
354
     * and insert it.
355
     */
356
0
    newnode = new_keynode(keyname, ds, keytable, managed, initial);
357
0
    result = dns_qp_insert(qp, newnode, 0);
358
0
    if (callback != NULL) {
359
0
      (*callback)(keyname, callback_arg);
360
0
    }
361
0
  } else {
362
    /*
363
     * A node already exists for "keyname" in "keytable".
364
     */
365
0
    if (ds != NULL) {
366
0
      dns_keynode_t *knode = pval;
367
0
      add_ds(knode, ds, keytable->mctx);
368
0
    }
369
0
    result = ISC_R_SUCCESS;
370
0
  }
371
372
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
373
0
  dns_qpmulti_commit(keytable->table, &qp);
374
375
0
  return result;
376
0
}
377
378
isc_result_t
379
dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
380
     dns_name_t *name, dns_rdata_ds_t *ds,
381
0
     dns_keytable_callback_t callback, void *callback_arg) {
382
0
  REQUIRE(ds != NULL);
383
0
  REQUIRE(!initial || managed);
384
385
0
  return insert(keytable, managed, initial, name, ds, callback,
386
0
          callback_arg);
387
0
}
388
389
isc_result_t
390
0
dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
391
0
  return insert(keytable, true, false, name, NULL, NULL, NULL);
392
0
}
393
394
isc_result_t
395
dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname,
396
0
        dns_keytable_callback_t callback, void *callback_arg) {
397
0
  isc_result_t result;
398
0
  dns_qp_t *qp = NULL;
399
0
  void *pval = NULL;
400
401
0
  REQUIRE(VALID_KEYTABLE(keytable));
402
0
  REQUIRE(keyname != NULL);
403
404
0
  dns_qpmulti_write(keytable->table, &qp);
405
0
  result = dns_qp_deletename(qp, keyname, DNS_DBNAMESPACE_NORMAL, &pval,
406
0
           NULL);
407
0
  if (result == ISC_R_SUCCESS) {
408
0
    dns_keynode_t *n = pval;
409
0
    if (callback != NULL) {
410
0
      (*callback)(keyname, callback_arg);
411
0
    }
412
0
    dns_keynode_detach(&n);
413
0
  }
414
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
415
0
  dns_qpmulti_commit(keytable->table, &qp);
416
417
0
  return result;
418
0
}
419
420
isc_result_t
421
dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
422
0
           dns_rdata_dnskey_t *dnskey) {
423
0
  isc_result_t result;
424
0
  dns_keynode_t *knode = NULL;
425
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
426
0
  unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
427
0
  dns_rdata_ds_t ds;
428
0
  isc_buffer_t b;
429
0
  dns_qp_t *qp = NULL;
430
0
  void *pval = NULL;
431
432
0
  REQUIRE(VALID_KEYTABLE(keytable));
433
0
  REQUIRE(dnskey != NULL);
434
435
0
  dns_qpmulti_write(keytable->table, &qp);
436
0
  result = dns_qp_getname(qp, keyname, DNS_DBNAMESPACE_NORMAL, &pval,
437
0
        NULL);
438
0
  if (result != ISC_R_SUCCESS) {
439
0
    goto finish;
440
0
  }
441
442
0
  knode = pval;
443
444
0
  RWLOCK(&knode->rwlock, isc_rwlocktype_read);
445
0
  if (knode->dslist == NULL) {
446
0
    RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
447
0
    result = DNS_R_PARTIALMATCH;
448
0
    goto finish;
449
0
  }
450
0
  RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
451
452
0
  isc_buffer_init(&b, data, sizeof(data));
453
0
  result = dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
454
0
              dns_rdatatype_dnskey, dnskey, &b);
455
0
  if (result != ISC_R_SUCCESS) {
456
0
    goto finish;
457
0
  }
458
459
0
  result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
460
0
             digest, sizeof(digest), &ds);
461
0
  if (result != ISC_R_SUCCESS) {
462
0
    goto finish;
463
0
  }
464
465
0
  result = delete_ds(qp, keytable, knode, &ds);
466
467
0
finish:
468
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
469
0
  dns_qpmulti_commit(keytable->table, &qp);
470
471
0
  return result;
472
0
}
473
474
isc_result_t
475
dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
476
0
      dns_keynode_t **keynodep) {
477
0
  isc_result_t result;
478
0
  dns_qpread_t qpr;
479
0
  void *pval = NULL;
480
481
0
  REQUIRE(VALID_KEYTABLE(keytable));
482
0
  REQUIRE(keyname != NULL);
483
0
  REQUIRE(keynodep != NULL && *keynodep == NULL);
484
485
0
  dns_qpmulti_query(keytable->table, &qpr);
486
0
  result = dns_qp_getname(&qpr, keyname, DNS_DBNAMESPACE_NORMAL, &pval,
487
0
        NULL);
488
0
  if (result == ISC_R_SUCCESS) {
489
0
    dns_keynode_t *knode = pval;
490
0
    dns_keynode_attach(knode, keynodep);
491
0
  }
492
0
  dns_qpread_destroy(keytable->table, &qpr);
493
494
0
  return result;
495
0
}
496
497
isc_result_t
498
dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
499
0
            dns_name_t *foundname) {
500
0
  isc_result_t result;
501
0
  dns_qpread_t qpr;
502
0
  dns_keynode_t *keynode = NULL;
503
0
  void *pval = NULL;
504
505
  /*
506
   * Search for the deepest match in 'keytable'.
507
   */
508
509
0
  REQUIRE(VALID_KEYTABLE(keytable));
510
0
  REQUIRE(dns_name_isabsolute(name));
511
0
  REQUIRE(foundname != NULL);
512
513
0
  dns_qpmulti_query(keytable->table, &qpr);
514
0
  result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NORMAL, NULL, NULL,
515
0
             &pval, NULL);
516
0
  keynode = pval;
517
518
0
  if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
519
0
    dns_name_copy(&keynode->name, foundname);
520
0
    result = ISC_R_SUCCESS;
521
0
  }
522
523
0
  dns_qpread_destroy(keytable->table, &qpr);
524
0
  return result;
525
0
}
526
527
bool
528
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
529
0
          dns_name_t *foundname) {
530
0
  isc_result_t result;
531
0
  dns_qpread_t qpr;
532
0
  dns_keynode_t *keynode = NULL;
533
0
  void *pval = NULL;
534
0
  bool secure = false;
535
536
  /*
537
   * Is 'name' at or beneath a trusted key?
538
   */
539
540
0
  REQUIRE(VALID_KEYTABLE(keytable));
541
0
  REQUIRE(dns_name_isabsolute(name));
542
543
0
  dns_qpmulti_query(keytable->table, &qpr);
544
0
  result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NORMAL, NULL, NULL,
545
0
             &pval, NULL);
546
0
  if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
547
0
    keynode = pval;
548
0
    if (foundname != NULL) {
549
0
      dns_name_copy(&keynode->name, foundname);
550
0
    }
551
0
    secure = true;
552
0
  }
553
554
0
  dns_qpread_destroy(keytable->table, &qpr);
555
556
0
  return secure;
557
0
}
558
559
static isc_result_t
560
0
putstr(isc_buffer_t *b, const char *str) {
561
0
  RETERR(isc_buffer_reserve(b, strlen(str)));
562
563
0
  isc_buffer_putstr(b, str);
564
0
  return ISC_R_SUCCESS;
565
0
}
566
567
isc_result_t
568
0
dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
569
0
  isc_result_t result;
570
0
  isc_buffer_t *text = NULL;
571
572
0
  REQUIRE(VALID_KEYTABLE(keytable));
573
0
  REQUIRE(fp != NULL);
574
575
0
  isc_buffer_allocate(keytable->mctx, &text, 4096);
576
577
0
  result = dns_keytable_totext(keytable, text);
578
579
0
  if (isc_buffer_usedlength(text) != 0) {
580
0
    (void)putstr(text, "\n");
581
0
  } else if (result == ISC_R_SUCCESS) {
582
0
    (void)putstr(text, "none");
583
0
  } else {
584
0
    (void)putstr(text, "could not dump key table: ");
585
0
    (void)putstr(text, isc_result_totext(result));
586
0
  }
587
588
0
  fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text),
589
0
    (char *)isc_buffer_base(text));
590
591
0
  isc_buffer_free(&text);
592
0
  return result;
593
0
}
594
595
static isc_result_t
596
0
keynode_dslist_totext(dns_keynode_t *keynode, isc_buffer_t *text) {
597
0
  isc_result_t result;
598
0
  char namebuf[DNS_NAME_FORMATSIZE];
599
0
  char obuf[DNS_NAME_FORMATSIZE + 200];
600
0
  dns_rdataset_t dsset;
601
602
0
  dns_rdataset_init(&dsset);
603
0
  if (!dns_keynode_dsset(keynode, &dsset)) {
604
0
    return ISC_R_SUCCESS;
605
0
  }
606
607
0
  dns_name_format(&keynode->name, namebuf, sizeof(namebuf));
608
609
0
  DNS_RDATASET_FOREACH(&dsset) {
610
0
    char algbuf[DNS_SECALG_FORMATSIZE];
611
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
612
0
    dns_rdata_ds_t ds;
613
614
0
    dns_rdataset_current(&dsset, &rdata);
615
0
    result = dns_rdata_tostruct(&rdata, &ds, NULL);
616
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
617
618
0
    dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
619
620
0
    RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
621
0
    snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
622
0
       algbuf, ds.key_tag,
623
0
       keynode->initial ? "initializing " : "",
624
0
       keynode->managed ? "managed" : "static");
625
0
    RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
626
627
0
    result = putstr(text, obuf);
628
0
    if (result != ISC_R_SUCCESS) {
629
0
      dns_rdataset_disassociate(&dsset);
630
0
      return result;
631
0
    }
632
0
  }
633
0
  dns_rdataset_disassociate(&dsset);
634
635
0
  return ISC_R_SUCCESS;
636
0
}
637
638
isc_result_t
639
0
dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t *text) {
640
0
  isc_result_t result = ISC_R_SUCCESS;
641
0
  dns_qpread_t qpr;
642
0
  dns_qpiter_t iter;
643
0
  void *pval = NULL;
644
645
0
  REQUIRE(VALID_KEYTABLE(keytable));
646
0
  REQUIRE(text != NULL);
647
648
0
  dns_qpmulti_query(keytable->table, &qpr);
649
0
  dns_qpiter_init(&qpr, &iter);
650
651
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
652
0
    dns_keynode_t *knode = pval;
653
0
    if (knode->dslist != NULL) {
654
0
      result = keynode_dslist_totext(knode, text);
655
0
      if (result != ISC_R_SUCCESS) {
656
0
        break;
657
0
      }
658
0
    }
659
0
  }
660
661
0
  dns_qpread_destroy(keytable->table, &qpr);
662
0
  return result;
663
0
}
664
665
void
666
dns_keytable_forall(dns_keytable_t *keytable,
667
        void (*func)(dns_keytable_t *, dns_keynode_t *,
668
         dns_name_t *, void *),
669
0
        void *arg) {
670
0
  dns_qpread_t qpr;
671
0
  dns_qpiter_t iter;
672
0
  void *pval = NULL;
673
674
0
  REQUIRE(VALID_KEYTABLE(keytable));
675
676
0
  dns_qpmulti_query(keytable->table, &qpr);
677
0
  dns_qpiter_init(&qpr, &iter);
678
679
0
  while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
680
0
    dns_keynode_t *knode = pval;
681
0
    (*func)(keytable, knode, &knode->name, arg);
682
0
  }
683
684
0
  dns_qpread_destroy(keytable->table, &qpr);
685
0
}
686
687
bool
688
0
dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
689
0
  bool result;
690
691
0
  REQUIRE(VALID_KEYNODE(keynode));
692
0
  REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
693
694
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
695
0
  if (keynode->dslist != NULL) {
696
0
    if (rdataset != NULL) {
697
0
      keynode_clone(&keynode->dsset,
698
0
              rdataset DNS__DB_FILELINE);
699
0
    }
700
0
    result = true;
701
0
  } else {
702
0
    result = false;
703
0
  }
704
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
705
0
  return result;
706
0
}
707
708
bool
709
0
dns_keynode_managed(dns_keynode_t *keynode) {
710
0
  bool managed;
711
712
0
  REQUIRE(VALID_KEYNODE(keynode));
713
714
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
715
0
  managed = keynode->managed;
716
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
717
718
0
  return managed;
719
0
}
720
721
bool
722
0
dns_keynode_initial(dns_keynode_t *keynode) {
723
0
  bool initial;
724
725
0
  REQUIRE(VALID_KEYNODE(keynode));
726
727
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
728
0
  initial = keynode->initial;
729
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
730
731
0
  return initial;
732
0
}
733
734
void
735
0
dns_keynode_trust(dns_keynode_t *keynode) {
736
0
  REQUIRE(VALID_KEYNODE(keynode));
737
738
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_write);
739
0
  keynode->initial = false;
740
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_write);
741
0
}
742
743
static void
744
0
keynode_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
745
0
  dns_keynode_t *keynode = NULL;
746
747
0
  rdataset->methods = NULL;
748
0
  keynode = rdataset->keytable.node;
749
0
  rdataset->keytable.node = NULL;
750
751
0
  dns_keynode_detach(&keynode);
752
0
}
753
754
static isc_result_t
755
0
keynode_first(dns_rdataset_t *rdataset) {
756
0
  dns_keynode_t *keynode = NULL;
757
758
0
  keynode = rdataset->keytable.node;
759
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
760
0
  rdataset->keytable.iter = ISC_LIST_HEAD(keynode->dslist->rdata);
761
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
762
763
0
  if (rdataset->keytable.iter == NULL) {
764
0
    return ISC_R_NOMORE;
765
0
  }
766
767
0
  return ISC_R_SUCCESS;
768
0
}
769
770
static isc_result_t
771
0
keynode_next(dns_rdataset_t *rdataset) {
772
0
  dns_keynode_t *keynode = NULL;
773
0
  dns_rdata_t *rdata = NULL;
774
775
0
  rdata = rdataset->keytable.iter;
776
0
  if (rdata == NULL) {
777
0
    return ISC_R_NOMORE;
778
0
  }
779
780
0
  keynode = rdataset->keytable.node;
781
0
  RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
782
0
  rdataset->keytable.iter = ISC_LIST_NEXT(rdata, link);
783
0
  RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
784
785
0
  if (rdataset->keytable.iter == NULL) {
786
0
    return ISC_R_NOMORE;
787
0
  }
788
789
0
  return ISC_R_SUCCESS;
790
0
}
791
792
static void
793
0
keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
794
0
  dns_rdata_t *list_rdata = NULL;
795
796
0
  list_rdata = rdataset->keytable.iter;
797
0
  INSIST(list_rdata != NULL);
798
799
0
  dns_rdata_clone(list_rdata, rdata);
800
0
}
801
802
static void
803
0
keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
804
0
  dns_keynode_t *keynode = NULL;
805
806
0
  keynode = source->keytable.node;
807
0
  isc_refcount_increment(&keynode->references);
808
809
0
  *target = *source;
810
0
  target->keytable.iter = NULL;
811
0
}
812
813
static void
814
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
815
0
    uint32_t ival ISC_ATTR_UNUSED) {
816
0
  dns_keynode_t *keynode = pval;
817
0
  dns_keynode_ref(keynode);
818
0
}
819
820
static void
821
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
822
0
    uint32_t ival ISC_ATTR_UNUSED) {
823
0
  dns_keynode_t *keynode = pval;
824
0
  dns_keynode_detach(&keynode);
825
0
}
826
827
static size_t
828
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
829
0
     uint32_t ival ISC_ATTR_UNUSED) {
830
0
  dns_keynode_t *keynode = pval;
831
0
  return dns_qpkey_fromname(key, &keynode->name, DNS_DBNAMESPACE_NORMAL);
832
0
}
833
834
static void
835
0
qp_triename(void *uctx, char *buf, size_t size) {
836
0
  dns_view_t *view = uctx;
837
0
  snprintf(buf, size, "view %s secroots table", view->name);
838
0
}