Coverage Report

Created: 2026-08-13 07:07

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