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