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