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