1 /* $NetBSD: ssu.c,v 1.10 2025/01/26 16:25:25 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/magic.h> 21 #include <isc/mem.h> 22 #include <isc/netaddr.h> 23 #include <isc/refcount.h> 24 #include <isc/result.h> 25 #include <isc/string.h> 26 #include <isc/util.h> 27 28 #include <dns/dlz.h> 29 #include <dns/fixedname.h> 30 #include <dns/name.h> 31 #include <dns/ssu.h> 32 33 #include <dst/dst.h> 34 #include <dst/gssapi.h> 35 36 #define SSUTABLEMAGIC ISC_MAGIC('S', 'S', 'U', 'T') 37 #define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC) 38 39 #define SSURULEMAGIC ISC_MAGIC('S', 'S', 'U', 'R') 40 #define VALID_SSURULE(table) ISC_MAGIC_VALID(table, SSURULEMAGIC) 41 42 struct dns_ssurule { 43 unsigned int magic; 44 bool grant; /*%< is this a grant or a deny? */ 45 dns_ssumatchtype_t matchtype; /*%< which type of pattern match? */ 46 dns_name_t *identity; /*%< the identity to match */ 47 dns_name_t *name; /*%< the name being updated */ 48 unsigned int ntypes; /*%< number of data types covered */ 49 dns_ssuruletype_t *types; /*%< the data types. Can include */ 50 /* ANY. if NULL, defaults to all */ 51 /* types except SIG, SOA, and NS */ 52 ISC_LINK(dns_ssurule_t) link; 53 }; 54 55 struct dns_ssutable { 56 unsigned int magic; 57 isc_mem_t *mctx; 58 isc_refcount_t references; 59 dns_dlzdb_t *dlzdatabase; 60 ISC_LIST(dns_ssurule_t) rules; 61 }; 62 63 void 64 dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) { 65 dns_ssutable_t *table; 66 67 REQUIRE(tablep != NULL && *tablep == NULL); 68 REQUIRE(mctx != NULL); 69 70 table = isc_mem_get(mctx, sizeof(*table)); 71 isc_refcount_init(&table->references, 1); 72 table->mctx = NULL; 73 isc_mem_attach(mctx, &table->mctx); 74 ISC_LIST_INIT(table->rules); 75 table->magic = SSUTABLEMAGIC; 76 *tablep = table; 77 } 78 79 static void 80 destroy(dns_ssutable_t *table) { 81 isc_mem_t *mctx; 82 83 REQUIRE(VALID_SSUTABLE(table)); 84 85 mctx = table->mctx; 86 while (!ISC_LIST_EMPTY(table->rules)) { 87 dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules); 88 if (rule->identity != NULL) { 89 dns_name_free(rule->identity, mctx); 90 isc_mem_put(mctx, rule->identity, 91 sizeof(*rule->identity)); 92 } 93 if (rule->name != NULL) { 94 dns_name_free(rule->name, mctx); 95 isc_mem_put(mctx, rule->name, sizeof(*rule->name)); 96 } 97 if (rule->types != NULL) { 98 isc_mem_cput(mctx, rule->types, rule->ntypes, 99 sizeof(*rule->types)); 100 } 101 ISC_LIST_UNLINK(table->rules, rule, link); 102 rule->magic = 0; 103 isc_mem_put(mctx, rule, sizeof(dns_ssurule_t)); 104 } 105 isc_refcount_destroy(&table->references); 106 table->magic = 0; 107 isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t)); 108 } 109 110 void 111 dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) { 112 REQUIRE(VALID_SSUTABLE(source)); 113 REQUIRE(targetp != NULL && *targetp == NULL); 114 115 isc_refcount_increment(&source->references); 116 117 *targetp = source; 118 } 119 120 void 121 dns_ssutable_detach(dns_ssutable_t **tablep) { 122 dns_ssutable_t *table; 123 124 REQUIRE(tablep != NULL); 125 table = *tablep; 126 *tablep = NULL; 127 REQUIRE(VALID_SSUTABLE(table)); 128 129 if (isc_refcount_decrement(&table->references) == 1) { 130 destroy(table); 131 } 132 } 133 134 void 135 dns_ssutable_addrule(dns_ssutable_t *table, bool grant, 136 const dns_name_t *identity, dns_ssumatchtype_t matchtype, 137 const dns_name_t *name, unsigned int ntypes, 138 dns_ssuruletype_t *types) { 139 dns_ssurule_t *rule; 140 isc_mem_t *mctx; 141 142 REQUIRE(VALID_SSUTABLE(table)); 143 REQUIRE(dns_name_isabsolute(identity)); 144 REQUIRE(dns_name_isabsolute(name)); 145 REQUIRE(matchtype <= dns_ssumatchtype_max); 146 if (matchtype == dns_ssumatchtype_wildcard) { 147 REQUIRE(dns_name_iswildcard(name)); 148 } 149 if (ntypes > 0) { 150 REQUIRE(types != NULL); 151 } 152 153 mctx = table->mctx; 154 rule = isc_mem_get(mctx, sizeof(*rule)); 155 156 rule->identity = NULL; 157 rule->name = NULL; 158 rule->types = NULL; 159 160 rule->grant = grant; 161 162 rule->identity = isc_mem_get(mctx, sizeof(*rule->identity)); 163 dns_name_init(rule->identity, NULL); 164 dns_name_dup(identity, mctx, rule->identity); 165 166 rule->name = isc_mem_get(mctx, sizeof(*rule->name)); 167 dns_name_init(rule->name, NULL); 168 dns_name_dup(name, mctx, rule->name); 169 170 rule->matchtype = matchtype; 171 172 rule->ntypes = ntypes; 173 if (ntypes > 0) { 174 rule->types = isc_mem_cget(mctx, ntypes, sizeof(*rule->types)); 175 memmove(rule->types, types, ntypes * sizeof(*rule->types)); 176 } else { 177 rule->types = NULL; 178 } 179 180 rule->magic = SSURULEMAGIC; 181 ISC_LIST_INITANDAPPEND(table->rules, rule, link); 182 } 183 184 static bool 185 isusertype(dns_rdatatype_t type) { 186 return type != dns_rdatatype_ns && type != dns_rdatatype_soa && 187 type != dns_rdatatype_rrsig; 188 } 189 190 static void 191 reverse_from_address(dns_name_t *tcpself, const isc_netaddr_t *tcpaddr) { 192 char buf[16 * 4 + sizeof("IP6.ARPA.")]; 193 isc_result_t result; 194 const unsigned char *ap; 195 isc_buffer_t b; 196 unsigned long l; 197 198 switch (tcpaddr->family) { 199 case AF_INET: 200 l = ntohl(tcpaddr->type.in.s_addr); 201 result = snprintf(buf, sizeof(buf), 202 "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.", 203 (l >> 0) & 0xff, (l >> 8) & 0xff, 204 (l >> 16) & 0xff, (l >> 24) & 0xff); 205 RUNTIME_CHECK(result < sizeof(buf)); 206 break; 207 case AF_INET6: 208 ap = tcpaddr->type.in6.s6_addr; 209 result = snprintf( 210 buf, sizeof(buf), 211 "%x.%x.%x.%x.%x.%x.%x.%x." 212 "%x.%x.%x.%x.%x.%x.%x.%x." 213 "%x.%x.%x.%x.%x.%x.%x.%x." 214 "%x.%x.%x.%x.%x.%x.%x.%x." 215 "IP6.ARPA.", 216 ap[15] & 0x0f, (ap[15] >> 4) & 0x0f, ap[14] & 0x0f, 217 (ap[14] >> 4) & 0x0f, ap[13] & 0x0f, 218 (ap[13] >> 4) & 0x0f, ap[12] & 0x0f, 219 (ap[12] >> 4) & 0x0f, ap[11] & 0x0f, 220 (ap[11] >> 4) & 0x0f, ap[10] & 0x0f, 221 (ap[10] >> 4) & 0x0f, ap[9] & 0x0f, (ap[9] >> 4) & 0x0f, 222 ap[8] & 0x0f, (ap[8] >> 4) & 0x0f, ap[7] & 0x0f, 223 (ap[7] >> 4) & 0x0f, ap[6] & 0x0f, (ap[6] >> 4) & 0x0f, 224 ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, ap[4] & 0x0f, 225 (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, (ap[3] >> 4) & 0x0f, 226 ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, ap[1] & 0x0f, 227 (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, (ap[0] >> 4) & 0x0f); 228 RUNTIME_CHECK(result < sizeof(buf)); 229 break; 230 default: 231 UNREACHABLE(); 232 } 233 isc_buffer_init(&b, buf, strlen(buf)); 234 isc_buffer_add(&b, strlen(buf)); 235 result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL); 236 RUNTIME_CHECK(result == ISC_R_SUCCESS); 237 } 238 239 static void 240 stf_from_address(dns_name_t *stfself, const isc_netaddr_t *tcpaddr) { 241 char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")]; 242 isc_result_t result; 243 const unsigned char *ap; 244 isc_buffer_t b; 245 unsigned long l; 246 247 switch (tcpaddr->family) { 248 case AF_INET: 249 l = ntohl(tcpaddr->type.in.s_addr); 250 result = snprintf( 251 buf, sizeof(buf), 252 "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.2.0.0.2.IP6.ARPA.", 253 l & 0xf, (l >> 4) & 0xf, (l >> 8) & 0xf, 254 (l >> 12) & 0xf, (l >> 16) & 0xf, (l >> 20) & 0xf, 255 (l >> 24) & 0xf, (l >> 28) & 0xf); 256 RUNTIME_CHECK(result < sizeof(buf)); 257 break; 258 case AF_INET6: 259 ap = tcpaddr->type.in6.s6_addr; 260 result = snprintf( 261 buf, sizeof(buf), 262 "%x.%x.%x.%x.%x.%x.%x.%x." 263 "%x.%x.%x.%x.IP6.ARPA.", 264 ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, ap[4] & 0x0f, 265 (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, (ap[3] >> 4) & 0x0f, 266 ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, ap[1] & 0x0f, 267 (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, (ap[0] >> 4) & 0x0f); 268 RUNTIME_CHECK(result < sizeof(buf)); 269 break; 270 default: 271 UNREACHABLE(); 272 } 273 isc_buffer_init(&b, buf, strlen(buf)); 274 isc_buffer_add(&b, strlen(buf)); 275 result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL); 276 RUNTIME_CHECK(result == ISC_R_SUCCESS); 277 } 278 279 bool 280 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, 281 const dns_name_t *name, const isc_netaddr_t *addr, 282 bool tcp, dns_aclenv_t *env, dns_rdatatype_t type, 283 const dns_name_t *target, const dst_key_t *key, 284 const dns_ssurule_t **rulep) { 285 dns_fixedname_t fixed; 286 dns_name_t *stfself; 287 dns_name_t *tcpself; 288 dns_name_t *wildcard; 289 dns_ssurule_t *rule; 290 const dns_name_t *tname; 291 int match; 292 isc_result_t result; 293 unsigned int i; 294 295 REQUIRE(VALID_SSUTABLE(table)); 296 REQUIRE(signer == NULL || dns_name_isabsolute(signer)); 297 REQUIRE(dns_name_isabsolute(name)); 298 REQUIRE(addr == NULL || env != NULL); 299 300 if (signer == NULL && addr == NULL) { 301 return false; 302 } 303 304 for (rule = ISC_LIST_HEAD(table->rules); rule != NULL; 305 rule = ISC_LIST_NEXT(rule, link)) 306 { 307 switch (rule->matchtype) { 308 case dns_ssumatchtype_local: 309 case dns_ssumatchtype_name: 310 case dns_ssumatchtype_self: 311 case dns_ssumatchtype_selfsub: 312 case dns_ssumatchtype_selfwild: 313 case dns_ssumatchtype_subdomain: 314 case dns_ssumatchtype_wildcard: 315 if (signer == NULL) { 316 continue; 317 } 318 if (dns_name_iswildcard(rule->identity)) { 319 if (!dns_name_matcheswildcard(signer, 320 rule->identity)) 321 { 322 continue; 323 } 324 } else { 325 if (!dns_name_equal(signer, rule->identity)) { 326 continue; 327 } 328 } 329 break; 330 case dns_ssumatchtype_selfkrb5: 331 case dns_ssumatchtype_selfms: 332 case dns_ssumatchtype_selfsubkrb5: 333 case dns_ssumatchtype_selfsubms: 334 case dns_ssumatchtype_subdomainkrb5: 335 case dns_ssumatchtype_subdomainms: 336 case dns_ssumatchtype_subdomainselfkrb5rhs: 337 case dns_ssumatchtype_subdomainselfmsrhs: 338 if (signer == NULL) { 339 continue; 340 } 341 break; 342 case dns_ssumatchtype_tcpself: 343 case dns_ssumatchtype_6to4self: 344 if (!tcp || addr == NULL) { 345 continue; 346 } 347 break; 348 case dns_ssumatchtype_external: 349 case dns_ssumatchtype_dlz: 350 break; 351 } 352 353 switch (rule->matchtype) { 354 case dns_ssumatchtype_name: 355 if (!dns_name_equal(name, rule->name)) { 356 continue; 357 } 358 break; 359 case dns_ssumatchtype_subdomain: 360 if (!dns_name_issubdomain(name, rule->name)) { 361 continue; 362 } 363 break; 364 case dns_ssumatchtype_local: 365 if (addr == NULL) { 366 continue; 367 } 368 if (!dns_name_issubdomain(name, rule->name)) { 369 continue; 370 } 371 rcu_read_lock(); 372 dns_acl_t *localhost = rcu_dereference(env->localhost); 373 dns_acl_match(addr, NULL, localhost, NULL, &match, 374 NULL); 375 rcu_read_unlock(); 376 if (match == 0) { 377 if (signer != NULL) { 378 isc_log_write(dns_lctx, 379 DNS_LOGCATEGORY_GENERAL, 380 DNS_LOGMODULE_SSU, 381 ISC_LOG_WARNING, 382 "update-policy local: " 383 "match on session " 384 "key not from " 385 "localhost"); 386 } 387 continue; 388 } 389 break; 390 case dns_ssumatchtype_wildcard: 391 if (!dns_name_matcheswildcard(name, rule->name)) { 392 continue; 393 } 394 break; 395 case dns_ssumatchtype_self: 396 if (!dns_name_equal(signer, name)) { 397 continue; 398 } 399 break; 400 case dns_ssumatchtype_selfsub: 401 if (!dns_name_issubdomain(name, signer)) { 402 continue; 403 } 404 break; 405 case dns_ssumatchtype_selfwild: 406 wildcard = dns_fixedname_initname(&fixed); 407 result = dns_name_concatenate(dns_wildcardname, signer, 408 wildcard, NULL); 409 if (result != ISC_R_SUCCESS) { 410 continue; 411 } 412 if (!dns_name_matcheswildcard(name, wildcard)) { 413 continue; 414 } 415 break; 416 case dns_ssumatchtype_selfkrb5: 417 if (dst_gssapi_identitymatchesrealmkrb5( 418 signer, name, rule->identity, false)) 419 { 420 break; 421 } 422 continue; 423 case dns_ssumatchtype_selfms: 424 if (dst_gssapi_identitymatchesrealmms( 425 signer, name, rule->identity, false)) 426 { 427 break; 428 } 429 continue; 430 case dns_ssumatchtype_selfsubkrb5: 431 if (dst_gssapi_identitymatchesrealmkrb5( 432 signer, name, rule->identity, true)) 433 { 434 break; 435 } 436 continue; 437 case dns_ssumatchtype_selfsubms: 438 if (dst_gssapi_identitymatchesrealmms( 439 signer, name, rule->identity, true)) 440 { 441 break; 442 } 443 continue; 444 case dns_ssumatchtype_subdomainkrb5: 445 case dns_ssumatchtype_subdomainselfkrb5rhs: 446 if (!dns_name_issubdomain(name, rule->name)) { 447 continue; 448 } 449 tname = NULL; 450 switch (rule->matchtype) { 451 case dns_ssumatchtype_subdomainselfkrb5rhs: 452 if (type == dns_rdatatype_ptr) { 453 tname = target; 454 } 455 if (type == dns_rdatatype_srv) { 456 tname = target; 457 } 458 break; 459 default: 460 break; 461 } 462 if (dst_gssapi_identitymatchesrealmkrb5( 463 signer, tname, rule->identity, false)) 464 { 465 break; 466 } 467 continue; 468 case dns_ssumatchtype_subdomainms: 469 case dns_ssumatchtype_subdomainselfmsrhs: 470 if (!dns_name_issubdomain(name, rule->name)) { 471 continue; 472 } 473 tname = NULL; 474 switch (rule->matchtype) { 475 case dns_ssumatchtype_subdomainselfmsrhs: 476 if (type == dns_rdatatype_ptr) { 477 tname = target; 478 } 479 if (type == dns_rdatatype_srv) { 480 tname = target; 481 } 482 break; 483 default: 484 break; 485 } 486 if (dst_gssapi_identitymatchesrealmms( 487 signer, tname, rule->identity, false)) 488 { 489 break; 490 } 491 continue; 492 case dns_ssumatchtype_tcpself: 493 tcpself = dns_fixedname_initname(&fixed); 494 reverse_from_address(tcpself, addr); 495 if (dns_name_iswildcard(rule->identity)) { 496 if (!dns_name_matcheswildcard(tcpself, 497 rule->identity)) 498 { 499 continue; 500 } 501 } else { 502 if (!dns_name_equal(tcpself, rule->identity)) { 503 continue; 504 } 505 } 506 if (!dns_name_equal(tcpself, name)) { 507 continue; 508 } 509 break; 510 case dns_ssumatchtype_6to4self: 511 stfself = dns_fixedname_initname(&fixed); 512 stf_from_address(stfself, addr); 513 if (dns_name_iswildcard(rule->identity)) { 514 if (!dns_name_matcheswildcard(stfself, 515 rule->identity)) 516 { 517 continue; 518 } 519 } else { 520 if (!dns_name_equal(stfself, rule->identity)) { 521 continue; 522 } 523 } 524 if (!dns_name_equal(stfself, name)) { 525 continue; 526 } 527 break; 528 case dns_ssumatchtype_external: 529 if (!dns_ssu_external_match(rule->identity, signer, 530 name, addr, type, key, 531 table->mctx)) 532 { 533 continue; 534 } 535 break; 536 case dns_ssumatchtype_dlz: 537 if (!dns_dlz_ssumatch(table->dlzdatabase, signer, name, 538 addr, type, key)) 539 { 540 continue; 541 } 542 break; 543 } 544 545 if (rule->ntypes == 0) { 546 /* 547 * If this is a DLZ rule, then the DLZ ssu 548 * checks will have already checked the type. 549 */ 550 if (rule->matchtype != dns_ssumatchtype_dlz && 551 !isusertype(type)) 552 { 553 continue; 554 } 555 } else { 556 for (i = 0; i < rule->ntypes; i++) { 557 if (rule->types[i].type == dns_rdatatype_any || 558 rule->types[i].type == type) 559 { 560 break; 561 } 562 } 563 if (i == rule->ntypes) { 564 continue; 565 } 566 } 567 if (rule->grant && rulep != NULL) { 568 *rulep = rule; 569 } 570 return rule->grant; 571 } 572 573 return false; 574 } 575 576 bool 577 dns_ssurule_isgrant(const dns_ssurule_t *rule) { 578 REQUIRE(VALID_SSURULE(rule)); 579 return rule->grant; 580 } 581 582 dns_name_t * 583 dns_ssurule_identity(const dns_ssurule_t *rule) { 584 REQUIRE(VALID_SSURULE(rule)); 585 return rule->identity; 586 } 587 588 unsigned int 589 dns_ssurule_matchtype(const dns_ssurule_t *rule) { 590 REQUIRE(VALID_SSURULE(rule)); 591 return rule->matchtype; 592 } 593 594 dns_name_t * 595 dns_ssurule_name(const dns_ssurule_t *rule) { 596 REQUIRE(VALID_SSURULE(rule)); 597 return rule->name; 598 } 599 600 unsigned int 601 dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types) { 602 REQUIRE(VALID_SSURULE(rule)); 603 REQUIRE(types != NULL && *types != NULL); 604 *types = rule->types; 605 return rule->ntypes; 606 } 607 608 unsigned int 609 dns_ssurule_max(const dns_ssurule_t *rule, dns_rdatatype_t type) { 610 unsigned int i; 611 unsigned int max = 0; 612 613 REQUIRE(VALID_SSURULE(rule)); 614 615 for (i = 0; i < rule->ntypes; i++) { 616 if (rule->types[i].type == dns_rdatatype_any) { 617 max = rule->types[i].max; 618 } 619 if (rule->types[i].type == type) { 620 return rule->types[i].max; 621 } 622 } 623 return max; 624 } 625 626 isc_result_t 627 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) { 628 REQUIRE(VALID_SSUTABLE(table)); 629 REQUIRE(rule != NULL && *rule == NULL); 630 *rule = ISC_LIST_HEAD(table->rules); 631 return *rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE; 632 } 633 634 isc_result_t 635 dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) { 636 REQUIRE(VALID_SSURULE(rule)); 637 REQUIRE(nextrule != NULL && *nextrule == NULL); 638 *nextrule = ISC_LIST_NEXT(rule, link); 639 return *nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE; 640 } 641 642 /* 643 * Create a specialised SSU table that points at an external DLZ database 644 */ 645 void 646 dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep, 647 dns_dlzdb_t *dlzdatabase) { 648 dns_ssurule_t *rule; 649 dns_ssutable_t *table = NULL; 650 651 REQUIRE(tablep != NULL && *tablep == NULL); 652 653 dns_ssutable_create(mctx, &table); 654 655 table->dlzdatabase = dlzdatabase; 656 657 rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t)); 658 659 rule->identity = NULL; 660 rule->name = NULL; 661 rule->grant = true; 662 rule->matchtype = dns_ssumatchtype_dlz; 663 rule->ntypes = 0; 664 rule->types = NULL; 665 rule->magic = SSURULEMAGIC; 666 667 ISC_LIST_INITANDAPPEND(table->rules, rule, link); 668 *tablep = table; 669 } 670 671 isc_result_t 672 dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) { 673 REQUIRE(str != NULL); 674 REQUIRE(mtype != NULL); 675 676 if (strcasecmp(str, "name") == 0) { 677 *mtype = dns_ssumatchtype_name; 678 } else if (strcasecmp(str, "subdomain") == 0) { 679 *mtype = dns_ssumatchtype_subdomain; 680 } else if (strcasecmp(str, "wildcard") == 0) { 681 *mtype = dns_ssumatchtype_wildcard; 682 } else if (strcasecmp(str, "self") == 0) { 683 *mtype = dns_ssumatchtype_self; 684 } else if (strcasecmp(str, "selfsub") == 0) { 685 *mtype = dns_ssumatchtype_selfsub; 686 } else if (strcasecmp(str, "selfwild") == 0) { 687 *mtype = dns_ssumatchtype_selfwild; 688 } else if (strcasecmp(str, "ms-self") == 0) { 689 *mtype = dns_ssumatchtype_selfms; 690 } else if (strcasecmp(str, "ms-selfsub") == 0) { 691 *mtype = dns_ssumatchtype_selfsubms; 692 } else if (strcasecmp(str, "krb5-self") == 0) { 693 *mtype = dns_ssumatchtype_selfkrb5; 694 } else if (strcasecmp(str, "krb5-selfsub") == 0) { 695 *mtype = dns_ssumatchtype_selfsubkrb5; 696 } else if (strcasecmp(str, "ms-subdomain") == 0) { 697 *mtype = dns_ssumatchtype_subdomainms; 698 } else if (strcasecmp(str, "ms-subdomain-self-rhs") == 0) { 699 *mtype = dns_ssumatchtype_subdomainselfmsrhs; 700 } else if (strcasecmp(str, "krb5-subdomain") == 0) { 701 *mtype = dns_ssumatchtype_subdomainkrb5; 702 } else if (strcasecmp(str, "krb5-subdomain-self-rhs") == 0) { 703 *mtype = dns_ssumatchtype_subdomainselfkrb5rhs; 704 } else if (strcasecmp(str, "tcp-self") == 0) { 705 *mtype = dns_ssumatchtype_tcpself; 706 } else if (strcasecmp(str, "6to4-self") == 0) { 707 *mtype = dns_ssumatchtype_6to4self; 708 } else if (strcasecmp(str, "zonesub") == 0) { 709 *mtype = dns_ssumatchtype_subdomain; 710 } else if (strcasecmp(str, "external") == 0) { 711 *mtype = dns_ssumatchtype_external; 712 } else { 713 return ISC_R_NOTFOUND; 714 } 715 return ISC_R_SUCCESS; 716 } 717