1 /* $NetBSD: keytable.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2009, 2010, 2013-2015 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 2000, 2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: keytable.c,v 1.41 2010/06/25 23:46:51 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/mem.h> 27 #include <isc/rwlock.h> 28 #include <isc/string.h> /* Required for HP/UX (and others?) */ 29 #include <isc/util.h> 30 31 #include <dns/keytable.h> 32 #include <dns/fixedname.h> 33 #include <dns/rbt.h> 34 #include <dns/result.h> 35 36 static void 37 free_keynode(void *node, void *arg) { 38 dns_keynode_t *keynode = node; 39 isc_mem_t *mctx = arg; 40 41 dns_keynode_detachall(mctx, &keynode); 42 } 43 44 isc_result_t 45 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) { 46 dns_keytable_t *keytable; 47 isc_result_t result; 48 49 /* 50 * Create a keytable. 51 */ 52 53 REQUIRE(keytablep != NULL && *keytablep == NULL); 54 55 keytable = isc_mem_get(mctx, sizeof(*keytable)); 56 if (keytable == NULL) 57 return (ISC_R_NOMEMORY); 58 59 keytable->table = NULL; 60 result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table); 61 if (result != ISC_R_SUCCESS) 62 goto cleanup_keytable; 63 64 result = isc_mutex_init(&keytable->lock); 65 if (result != ISC_R_SUCCESS) 66 goto cleanup_rbt; 67 68 result = isc_rwlock_init(&keytable->rwlock, 0, 0); 69 if (result != ISC_R_SUCCESS) 70 goto cleanup_lock; 71 72 keytable->mctx = NULL; 73 isc_mem_attach(mctx, &keytable->mctx); 74 keytable->active_nodes = 0; 75 keytable->references = 1; 76 keytable->magic = KEYTABLE_MAGIC; 77 *keytablep = keytable; 78 79 return (ISC_R_SUCCESS); 80 81 cleanup_lock: 82 DESTROYLOCK(&keytable->lock); 83 84 cleanup_rbt: 85 dns_rbt_destroy(&keytable->table); 86 87 cleanup_keytable: 88 isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable)); 89 90 return (result); 91 } 92 93 void 94 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) { 95 96 /* 97 * Attach *targetp to source. 98 */ 99 100 REQUIRE(VALID_KEYTABLE(source)); 101 REQUIRE(targetp != NULL && *targetp == NULL); 102 103 RWLOCK(&source->rwlock, isc_rwlocktype_write); 104 105 INSIST(source->references > 0); 106 source->references++; 107 INSIST(source->references != 0); 108 109 RWUNLOCK(&source->rwlock, isc_rwlocktype_write); 110 111 *targetp = source; 112 } 113 114 void 115 dns_keytable_detach(dns_keytable_t **keytablep) { 116 isc_boolean_t destroy = ISC_FALSE; 117 dns_keytable_t *keytable; 118 119 /* 120 * Detach *keytablep from its keytable. 121 */ 122 123 REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep)); 124 125 keytable = *keytablep; 126 127 RWLOCK(&keytable->rwlock, isc_rwlocktype_write); 128 129 INSIST(keytable->references > 0); 130 keytable->references--; 131 LOCK(&keytable->lock); 132 if (keytable->references == 0 && keytable->active_nodes == 0) 133 destroy = ISC_TRUE; 134 UNLOCK(&keytable->lock); 135 136 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); 137 138 if (destroy) { 139 dns_rbt_destroy(&keytable->table); 140 isc_rwlock_destroy(&keytable->rwlock); 141 DESTROYLOCK(&keytable->lock); 142 keytable->magic = 0; 143 isc_mem_putanddetach(&keytable->mctx, 144 keytable, sizeof(*keytable)); 145 } 146 147 *keytablep = NULL; 148 } 149 150 static isc_result_t 151 insert(dns_keytable_t *keytable, isc_boolean_t managed, 152 dns_name_t *keyname, dst_key_t **keyp) 153 { 154 isc_result_t result; 155 dns_keynode_t *knode = NULL; 156 dns_rbtnode_t *node; 157 158 REQUIRE(keyp == NULL || *keyp != NULL); 159 REQUIRE(VALID_KEYTABLE(keytable)); 160 161 result = dns_keynode_create(keytable->mctx, &knode); 162 if (result != ISC_R_SUCCESS) 163 return (result); 164 165 knode->managed = managed; 166 167 RWLOCK(&keytable->rwlock, isc_rwlocktype_write); 168 169 node = NULL; 170 result = dns_rbt_addnode(keytable->table, keyname, &node); 171 172 if (keyp != NULL) { 173 if (result == ISC_R_EXISTS) { 174 /* Key already in table? */ 175 dns_keynode_t *k; 176 for (k = node->data; k != NULL; k = k->next) { 177 if (k->key == NULL) { 178 k->key = *keyp; 179 *keyp = NULL; /* transfer ownership */ 180 break; 181 } 182 if (dst_key_compare(k->key, *keyp) == ISC_TRUE) 183 break; 184 } 185 186 if (k == NULL) 187 result = ISC_R_SUCCESS; 188 else if (*keyp != NULL) 189 dst_key_free(keyp); 190 } 191 192 if (result == ISC_R_SUCCESS) { 193 knode->key = *keyp; 194 knode->next = node->data; 195 *keyp = NULL; 196 } 197 } 198 199 if (result == ISC_R_SUCCESS) { 200 node->data = knode; 201 knode = NULL; 202 } 203 204 /* Key was already there? That's the same as a success */ 205 if (result == ISC_R_EXISTS) 206 result = ISC_R_SUCCESS; 207 208 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); 209 210 if (knode != NULL) 211 dns_keynode_detach(keytable->mctx, &knode); 212 213 return (result); 214 } 215 216 isc_result_t 217 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed, 218 dst_key_t **keyp) 219 { 220 REQUIRE(keyp != NULL && *keyp != NULL); 221 return (insert(keytable, managed, dst_key_name(*keyp), keyp)); 222 } 223 224 isc_result_t 225 dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) { 226 return (insert(keytable, ISC_TRUE, name, NULL)); 227 } 228 229 isc_result_t 230 dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) { 231 isc_result_t result; 232 dns_rbtnode_t *node = NULL; 233 234 REQUIRE(VALID_KEYTABLE(keytable)); 235 REQUIRE(keyname != NULL); 236 237 RWLOCK(&keytable->rwlock, isc_rwlocktype_write); 238 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, 239 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 240 if (result == ISC_R_SUCCESS) { 241 if (node->data != NULL) 242 result = dns_rbt_deletenode(keytable->table, 243 node, ISC_FALSE); 244 else 245 result = ISC_R_NOTFOUND; 246 } else if (result == DNS_R_PARTIALMATCH) 247 result = ISC_R_NOTFOUND; 248 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); 249 250 return (result); 251 } 252 253 isc_result_t 254 dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) { 255 isc_result_t result; 256 dns_name_t *keyname; 257 dns_rbtnode_t *node = NULL; 258 dns_keynode_t *knode = NULL, **kprev = NULL; 259 260 REQUIRE(VALID_KEYTABLE(keytable)); 261 REQUIRE(dstkey != NULL); 262 263 keyname = dst_key_name(dstkey); 264 265 RWLOCK(&keytable->rwlock, isc_rwlocktype_write); 266 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, 267 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 268 269 if (result == DNS_R_PARTIALMATCH) 270 result = ISC_R_NOTFOUND; 271 if (result != ISC_R_SUCCESS) 272 goto finish; 273 274 if (node->data == NULL) { 275 result = ISC_R_NOTFOUND; 276 goto finish; 277 } 278 279 knode = node->data; 280 if (knode->next == NULL && knode->key != NULL && 281 dst_key_compare(knode->key, dstkey) == ISC_TRUE) 282 { 283 result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE); 284 goto finish; 285 } 286 287 kprev = (dns_keynode_t **)(void *)&node->data; 288 while (knode != NULL) { 289 if (knode->key != NULL && 290 dst_key_compare(knode->key, dstkey) == ISC_TRUE) 291 break; 292 kprev = &knode->next; 293 knode = knode->next; 294 } 295 296 if (knode != NULL) { 297 if (knode->key != NULL) 298 dst_key_free(&knode->key); 299 /* 300 * This is equivalent to: 301 * dns_keynode_attach(knode->next, &tmp); 302 * dns_keynode_detach(kprev); 303 * dns_keynode_attach(tmp, &kprev); 304 * dns_keynode_detach(&tmp); 305 */ 306 *kprev = knode->next; 307 knode->next = NULL; 308 dns_keynode_detach(keytable->mctx, &knode); 309 } else 310 result = DNS_R_PARTIALMATCH; 311 finish: 312 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); 313 return (result); 314 } 315 316 isc_result_t 317 dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname, 318 dns_keynode_t **keynodep) 319 { 320 isc_result_t result; 321 dns_rbtnode_t *node = NULL; 322 323 REQUIRE(VALID_KEYTABLE(keytable)); 324 REQUIRE(keyname != NULL); 325 REQUIRE(keynodep != NULL && *keynodep == NULL); 326 327 RWLOCK(&keytable->rwlock, isc_rwlocktype_read); 328 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, 329 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 330 if (result == ISC_R_SUCCESS) { 331 if (node->data != NULL) { 332 LOCK(&keytable->lock); 333 keytable->active_nodes++; 334 UNLOCK(&keytable->lock); 335 dns_keynode_attach(node->data, keynodep); 336 } else 337 result = ISC_R_NOTFOUND; 338 } else if (result == DNS_R_PARTIALMATCH) 339 result = ISC_R_NOTFOUND; 340 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); 341 342 return (result); 343 } 344 345 isc_result_t 346 dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, 347 dns_keynode_t **nextnodep) 348 { 349 /* 350 * Return the next key after 'keynode', regardless of 351 * properties. 352 */ 353 354 REQUIRE(VALID_KEYTABLE(keytable)); 355 REQUIRE(VALID_KEYNODE(keynode)); 356 REQUIRE(nextnodep != NULL && *nextnodep == NULL); 357 358 if (keynode->next == NULL) 359 return (ISC_R_NOTFOUND); 360 361 dns_keynode_attach(keynode->next, nextnodep); 362 LOCK(&keytable->lock); 363 keytable->active_nodes++; 364 UNLOCK(&keytable->lock); 365 366 return (ISC_R_SUCCESS); 367 } 368 369 isc_result_t 370 dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, 371 dns_secalg_t algorithm, dns_keytag_t tag, 372 dns_keynode_t **keynodep) 373 { 374 isc_result_t result; 375 dns_keynode_t *knode; 376 void *data; 377 378 /* 379 * Search for a key named 'name', matching 'algorithm' and 'tag' in 380 * 'keytable'. 381 */ 382 383 REQUIRE(VALID_KEYTABLE(keytable)); 384 REQUIRE(dns_name_isabsolute(name)); 385 REQUIRE(keynodep != NULL && *keynodep == NULL); 386 387 RWLOCK(&keytable->rwlock, isc_rwlocktype_read); 388 389 /* 390 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname() 391 * as that indicates that 'name' was not found. 392 * 393 * DNS_R_PARTIALMATCH indicates that the name was found but we 394 * didn't get a match on algorithm and key id arguments. 395 */ 396 knode = NULL; 397 data = NULL; 398 result = dns_rbt_findname(keytable->table, name, 0, NULL, &data); 399 400 if (result == ISC_R_SUCCESS) { 401 INSIST(data != NULL); 402 for (knode = data; knode != NULL; knode = knode->next) { 403 if (knode->key == NULL) { 404 knode = NULL; 405 break; 406 } 407 if (algorithm == dst_key_alg(knode->key) 408 && tag == dst_key_id(knode->key)) 409 break; 410 } 411 if (knode != NULL) { 412 LOCK(&keytable->lock); 413 keytable->active_nodes++; 414 UNLOCK(&keytable->lock); 415 dns_keynode_attach(knode, keynodep); 416 } else 417 result = DNS_R_PARTIALMATCH; 418 } else if (result == DNS_R_PARTIALMATCH) 419 result = ISC_R_NOTFOUND; 420 421 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); 422 423 return (result); 424 } 425 426 isc_result_t 427 dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, 428 dns_keynode_t **nextnodep) 429 { 430 isc_result_t result; 431 dns_keynode_t *knode; 432 433 /* 434 * Search for the next key with the same properties as 'keynode' in 435 * 'keytable'. 436 */ 437 438 REQUIRE(VALID_KEYTABLE(keytable)); 439 REQUIRE(VALID_KEYNODE(keynode)); 440 REQUIRE(nextnodep != NULL && *nextnodep == NULL); 441 442 for (knode = keynode->next; knode != NULL; knode = knode->next) { 443 if (knode->key == NULL) { 444 knode = NULL; 445 break; 446 } 447 if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) && 448 dst_key_id(keynode->key) == dst_key_id(knode->key)) 449 break; 450 } 451 if (knode != NULL) { 452 LOCK(&keytable->lock); 453 keytable->active_nodes++; 454 UNLOCK(&keytable->lock); 455 result = ISC_R_SUCCESS; 456 dns_keynode_attach(knode, nextnodep); 457 } else 458 result = ISC_R_NOTFOUND; 459 460 return (result); 461 } 462 463 isc_result_t 464 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name, 465 dns_name_t *foundname) 466 { 467 isc_result_t result; 468 void *data; 469 470 /* 471 * Search for the deepest match in 'keytable'. 472 */ 473 474 REQUIRE(VALID_KEYTABLE(keytable)); 475 REQUIRE(dns_name_isabsolute(name)); 476 REQUIRE(foundname != NULL); 477 478 RWLOCK(&keytable->rwlock, isc_rwlocktype_read); 479 480 data = NULL; 481 result = dns_rbt_findname(keytable->table, name, 0, foundname, &data); 482 483 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 484 result = ISC_R_SUCCESS; 485 486 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); 487 488 return (result); 489 } 490 491 void 492 dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source, 493 dns_keynode_t **target) 494 { 495 /* 496 * Give back a keynode found via dns_keytable_findkeynode(). 497 */ 498 499 REQUIRE(VALID_KEYTABLE(keytable)); 500 REQUIRE(VALID_KEYNODE(source)); 501 REQUIRE(target != NULL && *target == NULL); 502 503 LOCK(&keytable->lock); 504 keytable->active_nodes++; 505 UNLOCK(&keytable->lock); 506 507 dns_keynode_attach(source, target); 508 } 509 510 void 511 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) 512 { 513 /* 514 * Give back a keynode found via dns_keytable_findkeynode(). 515 */ 516 517 REQUIRE(VALID_KEYTABLE(keytable)); 518 REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep)); 519 520 LOCK(&keytable->lock); 521 INSIST(keytable->active_nodes > 0); 522 keytable->active_nodes--; 523 UNLOCK(&keytable->lock); 524 525 dns_keynode_detach(keytable->mctx, keynodep); 526 } 527 528 isc_result_t 529 dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name, 530 isc_boolean_t *wantdnssecp) 531 { 532 isc_result_t result; 533 void *data; 534 535 /* 536 * Is 'name' at or beneath a trusted key? 537 */ 538 539 REQUIRE(VALID_KEYTABLE(keytable)); 540 REQUIRE(dns_name_isabsolute(name)); 541 REQUIRE(wantdnssecp != NULL); 542 543 RWLOCK(&keytable->rwlock, isc_rwlocktype_read); 544 545 data = NULL; 546 result = dns_rbt_findname(keytable->table, name, 0, NULL, &data); 547 548 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { 549 INSIST(data != NULL); 550 *wantdnssecp = ISC_TRUE; 551 result = ISC_R_SUCCESS; 552 } else if (result == ISC_R_NOTFOUND) { 553 *wantdnssecp = ISC_FALSE; 554 result = ISC_R_SUCCESS; 555 } 556 557 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); 558 559 return (result); 560 } 561 562 isc_result_t 563 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) 564 { 565 isc_result_t result; 566 dns_keynode_t *knode; 567 dns_rbtnode_t *node; 568 dns_rbtnodechain_t chain; 569 570 REQUIRE(VALID_KEYTABLE(keytable)); 571 572 RWLOCK(&keytable->rwlock, isc_rwlocktype_read); 573 dns_rbtnodechain_init(&chain, keytable->mctx); 574 result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL); 575 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) 576 goto cleanup; 577 for (;;) { 578 char pbuf[DST_KEY_FORMATSIZE]; 579 580 dns_rbtnodechain_current(&chain, NULL, NULL, &node); 581 for (knode = node->data; knode != NULL; knode = knode->next) { 582 if (knode->key == NULL) 583 continue; 584 dst_key_format(knode->key, pbuf, sizeof(pbuf)); 585 fprintf(fp, "%s ; %s\n", pbuf, 586 knode->managed ? "managed" : "trusted"); 587 } 588 result = dns_rbtnodechain_next(&chain, NULL, NULL); 589 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 590 if (result == ISC_R_NOMORE) 591 result = ISC_R_SUCCESS; 592 break; 593 } 594 } 595 596 cleanup: 597 dns_rbtnodechain_invalidate(&chain); 598 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); 599 return (result); 600 } 601 602 dst_key_t * 603 dns_keynode_key(dns_keynode_t *keynode) { 604 605 /* 606 * Get the DST key associated with keynode. 607 */ 608 609 REQUIRE(VALID_KEYNODE(keynode)); 610 611 return (keynode->key); 612 } 613 614 isc_boolean_t 615 dns_keynode_managed(dns_keynode_t *keynode) { 616 /* 617 * Is this a managed key? 618 */ 619 REQUIRE(VALID_KEYNODE(keynode)); 620 621 return (keynode->managed); 622 } 623 624 isc_result_t 625 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) { 626 isc_result_t result; 627 dns_keynode_t *knode = NULL; 628 629 REQUIRE(target != NULL && *target == NULL); 630 631 knode = isc_mem_get(mctx, sizeof(dns_keynode_t)); 632 if (knode == NULL) 633 return (ISC_R_NOMEMORY); 634 635 knode->magic = KEYNODE_MAGIC; 636 knode->managed = ISC_FALSE; 637 knode->key = NULL; 638 knode->next = NULL; 639 640 result = isc_refcount_init(&knode->refcount, 1); 641 if (result != ISC_R_SUCCESS) 642 return (result); 643 644 *target = knode; 645 return (ISC_R_SUCCESS); 646 } 647 648 void 649 dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) { 650 REQUIRE(VALID_KEYNODE(source)); 651 isc_refcount_increment(&source->refcount, NULL); 652 *target = source; 653 } 654 655 void 656 dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) { 657 unsigned int refs; 658 dns_keynode_t *node = *keynode; 659 REQUIRE(VALID_KEYNODE(node)); 660 isc_refcount_decrement(&node->refcount, &refs); 661 if (refs == 0) { 662 if (node->key != NULL) 663 dst_key_free(&node->key); 664 isc_refcount_destroy(&node->refcount); 665 isc_mem_put(mctx, node, sizeof(dns_keynode_t)); 666 } 667 *keynode = NULL; 668 } 669 670 void 671 dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) { 672 dns_keynode_t *next = NULL, *node = *keynode; 673 REQUIRE(VALID_KEYNODE(node)); 674 while (node != NULL) { 675 next = node->next; 676 dns_keynode_detach(mctx, &node); 677 node = next; 678 } 679 *keynode = NULL; 680 } 681