"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/ssu.c" (4 Sep 2020, 17741 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ssu.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <stdbool.h>
   15 
   16 #include <isc/magic.h>
   17 #include <isc/mem.h>
   18 #include <isc/netaddr.h>
   19 #include <isc/print.h>
   20 #include <isc/refcount.h>
   21 #include <isc/result.h>
   22 #include <isc/string.h>
   23 #include <isc/util.h>
   24 
   25 #include <dns/dlz.h>
   26 #include <dns/fixedname.h>
   27 #include <dns/name.h>
   28 #include <dns/ssu.h>
   29 
   30 #include <dst/dst.h>
   31 #include <dst/gssapi.h>
   32 
   33 #define SSUTABLEMAGIC         ISC_MAGIC('S', 'S', 'U', 'T')
   34 #define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
   35 
   36 #define SSURULEMAGIC         ISC_MAGIC('S', 'S', 'U', 'R')
   37 #define VALID_SSURULE(table) ISC_MAGIC_VALID(table, SSURULEMAGIC)
   38 
   39 struct dns_ssurule {
   40     unsigned int magic;
   41     bool grant;           /*%< is this a grant or a deny? */
   42     dns_ssumatchtype_t matchtype; /*%< which type of pattern match? */
   43     dns_name_t *identity;         /*%< the identity to match */
   44     dns_name_t *name;         /*%< the name being updated */
   45     unsigned int ntypes;          /*%< number of data types covered */
   46     dns_ssuruletype_t *types;     /*%< the data types.  Can include */
   47                       /*   ANY. if NULL, defaults to all */
   48                       /*   types except SIG, SOA, and NS */
   49     ISC_LINK(dns_ssurule_t) link;
   50 };
   51 
   52 struct dns_ssutable {
   53     unsigned int magic;
   54     isc_mem_t *mctx;
   55     isc_refcount_t references;
   56     dns_dlzdb_t *dlzdatabase;
   57     ISC_LIST(dns_ssurule_t) rules;
   58 };
   59 
   60 isc_result_t
   61 dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
   62     dns_ssutable_t *table;
   63 
   64     REQUIRE(tablep != NULL && *tablep == NULL);
   65     REQUIRE(mctx != NULL);
   66 
   67     table = isc_mem_get(mctx, sizeof(dns_ssutable_t));
   68     isc_refcount_init(&table->references, 1);
   69     table->mctx = NULL;
   70     isc_mem_attach(mctx, &table->mctx);
   71     ISC_LIST_INIT(table->rules);
   72     table->magic = SSUTABLEMAGIC;
   73     *tablep = table;
   74     return (ISC_R_SUCCESS);
   75 }
   76 
   77 static inline void
   78 destroy(dns_ssutable_t *table) {
   79     isc_mem_t *mctx;
   80 
   81     REQUIRE(VALID_SSUTABLE(table));
   82 
   83     mctx = table->mctx;
   84     while (!ISC_LIST_EMPTY(table->rules)) {
   85         dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
   86         if (rule->identity != NULL) {
   87             dns_name_free(rule->identity, mctx);
   88             isc_mem_put(mctx, rule->identity,
   89                     sizeof(*rule->identity));
   90         }
   91         if (rule->name != NULL) {
   92             dns_name_free(rule->name, mctx);
   93             isc_mem_put(mctx, rule->name, sizeof(*rule->name));
   94         }
   95         if (rule->types != NULL) {
   96             isc_mem_put(mctx, rule->types,
   97                     rule->ntypes * sizeof(*rule->types));
   98         }
   99         ISC_LIST_UNLINK(table->rules, rule, link);
  100         rule->magic = 0;
  101         isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
  102     }
  103     isc_refcount_destroy(&table->references);
  104     table->magic = 0;
  105     isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t));
  106 }
  107 
  108 void
  109 dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
  110     REQUIRE(VALID_SSUTABLE(source));
  111     REQUIRE(targetp != NULL && *targetp == NULL);
  112 
  113     isc_refcount_increment(&source->references);
  114 
  115     *targetp = source;
  116 }
  117 
  118 void
  119 dns_ssutable_detach(dns_ssutable_t **tablep) {
  120     dns_ssutable_t *table;
  121 
  122     REQUIRE(tablep != NULL);
  123     table = *tablep;
  124     *tablep = NULL;
  125     REQUIRE(VALID_SSUTABLE(table));
  126 
  127     if (isc_refcount_decrement(&table->references) == 1) {
  128         destroy(table);
  129     }
  130 }
  131 
  132 isc_result_t
  133 dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
  134              const dns_name_t *identity, dns_ssumatchtype_t matchtype,
  135              const dns_name_t *name, unsigned int ntypes,
  136              dns_ssuruletype_t *types) {
  137     dns_ssurule_t *rule;
  138     isc_mem_t *mctx;
  139 
  140     REQUIRE(VALID_SSUTABLE(table));
  141     REQUIRE(dns_name_isabsolute(identity));
  142     REQUIRE(dns_name_isabsolute(name));
  143     REQUIRE(matchtype <= dns_ssumatchtype_max);
  144     if (matchtype == dns_ssumatchtype_wildcard) {
  145         REQUIRE(dns_name_iswildcard(name));
  146     }
  147     if (ntypes > 0) {
  148         REQUIRE(types != NULL);
  149     }
  150 
  151     mctx = table->mctx;
  152     rule = isc_mem_get(mctx, sizeof(*rule));
  153 
  154     rule->identity = NULL;
  155     rule->name = NULL;
  156     rule->types = NULL;
  157 
  158     rule->grant = grant;
  159 
  160     rule->identity = isc_mem_get(mctx, sizeof(*rule->identity));
  161     dns_name_init(rule->identity, NULL);
  162     dns_name_dup(identity, mctx, rule->identity);
  163 
  164     rule->name = isc_mem_get(mctx, sizeof(*rule->name));
  165     dns_name_init(rule->name, NULL);
  166     dns_name_dup(name, mctx, rule->name);
  167 
  168     rule->matchtype = matchtype;
  169 
  170     rule->ntypes = ntypes;
  171     if (ntypes > 0) {
  172         rule->types = isc_mem_get(mctx, ntypes * sizeof(*rule->types));
  173         memmove(rule->types, types, ntypes * sizeof(*rule->types));
  174     } else {
  175         rule->types = NULL;
  176     }
  177 
  178     rule->magic = SSURULEMAGIC;
  179     ISC_LIST_INITANDAPPEND(table->rules, rule, link);
  180 
  181     return (ISC_R_SUCCESS);
  182 }
  183 
  184 static inline 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         INSIST(0);
  232         ISC_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 
  240 static void
  241 stf_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         INSIST(0);
  274         ISC_UNREACHABLE();
  275     }
  276     isc_buffer_init(&b, buf, strlen(buf));
  277     isc_buffer_add(&b, strlen(buf));
  278     result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
  279     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  280 }
  281 
  282 bool
  283 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
  284             const dns_name_t *name, const isc_netaddr_t *addr,
  285             bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type,
  286             const dst_key_t *key, 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     int match;
  293     isc_result_t result;
  294     unsigned int i;
  295 
  296     REQUIRE(VALID_SSUTABLE(table));
  297     REQUIRE(signer == NULL || dns_name_isabsolute(signer));
  298     REQUIRE(dns_name_isabsolute(name));
  299     REQUIRE(addr == NULL || env != NULL);
  300 
  301     if (signer == NULL && addr == NULL) {
  302         return (false);
  303     }
  304 
  305     for (rule = ISC_LIST_HEAD(table->rules); rule != NULL;
  306          rule = ISC_LIST_NEXT(rule, link))
  307     {
  308         switch (rule->matchtype) {
  309         case dns_ssumatchtype_name:
  310         case dns_ssumatchtype_local:
  311         case dns_ssumatchtype_subdomain:
  312         case dns_ssumatchtype_wildcard:
  313         case dns_ssumatchtype_self:
  314         case dns_ssumatchtype_selfsub:
  315         case dns_ssumatchtype_selfwild:
  316             if (signer == NULL) {
  317                 continue;
  318             }
  319             if (dns_name_iswildcard(rule->identity)) {
  320                 if (!dns_name_matcheswildcard(signer,
  321                                   rule->identity)) {
  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             if (signer == NULL) {
  337                 continue;
  338             }
  339             break;
  340         case dns_ssumatchtype_tcpself:
  341         case dns_ssumatchtype_6to4self:
  342             if (!tcp || addr == NULL) {
  343                 continue;
  344             }
  345             break;
  346         case dns_ssumatchtype_external:
  347         case dns_ssumatchtype_dlz:
  348             break;
  349         }
  350 
  351         switch (rule->matchtype) {
  352         case dns_ssumatchtype_name:
  353             if (!dns_name_equal(name, rule->name)) {
  354                 continue;
  355             }
  356             break;
  357         case dns_ssumatchtype_subdomain:
  358             if (!dns_name_issubdomain(name, rule->name)) {
  359                 continue;
  360             }
  361             break;
  362         case dns_ssumatchtype_local:
  363             if (addr == NULL) {
  364                 continue;
  365             }
  366             if (!dns_name_issubdomain(name, rule->name)) {
  367                 continue;
  368             }
  369             dns_acl_match(addr, NULL, env->localhost, NULL, &match,
  370                       NULL);
  371             if (match == 0) {
  372                 if (signer != NULL) {
  373                     isc_log_write(dns_lctx,
  374                               DNS_LOGCATEGORY_GENERAL,
  375                               DNS_LOGMODULE_SSU,
  376                               ISC_LOG_WARNING,
  377                               "update-policy local: "
  378                               "match on session "
  379                               "key not from "
  380                               "localhost");
  381                 }
  382                 continue;
  383             }
  384             break;
  385         case dns_ssumatchtype_wildcard:
  386             if (!dns_name_matcheswildcard(name, rule->name)) {
  387                 continue;
  388             }
  389             break;
  390         case dns_ssumatchtype_self:
  391             if (!dns_name_equal(signer, name)) {
  392                 continue;
  393             }
  394             break;
  395         case dns_ssumatchtype_selfsub:
  396             if (!dns_name_issubdomain(name, signer)) {
  397                 continue;
  398             }
  399             break;
  400         case dns_ssumatchtype_selfwild:
  401             wildcard = dns_fixedname_initname(&fixed);
  402             result = dns_name_concatenate(dns_wildcardname, signer,
  403                               wildcard, NULL);
  404             if (result != ISC_R_SUCCESS) {
  405                 continue;
  406             }
  407             if (!dns_name_matcheswildcard(name, wildcard)) {
  408                 continue;
  409             }
  410             break;
  411         case dns_ssumatchtype_selfkrb5:
  412             if (dst_gssapi_identitymatchesrealmkrb5(
  413                     signer, name, rule->identity, false)) {
  414                 break;
  415             }
  416             continue;
  417         case dns_ssumatchtype_selfms:
  418             if (dst_gssapi_identitymatchesrealmms(
  419                     signer, name, rule->identity, false)) {
  420                 break;
  421             }
  422             continue;
  423         case dns_ssumatchtype_selfsubkrb5:
  424             if (dst_gssapi_identitymatchesrealmkrb5(
  425                     signer, name, rule->identity, true)) {
  426                 break;
  427             }
  428             continue;
  429         case dns_ssumatchtype_selfsubms:
  430             if (dst_gssapi_identitymatchesrealmms(
  431                     signer, name, rule->identity, true)) {
  432                 break;
  433             }
  434             continue;
  435         case dns_ssumatchtype_subdomainkrb5:
  436             if (!dns_name_issubdomain(name, rule->name)) {
  437                 continue;
  438             }
  439             if (dst_gssapi_identitymatchesrealmkrb5(
  440                     signer, NULL, rule->identity, false)) {
  441                 break;
  442             }
  443             continue;
  444         case dns_ssumatchtype_subdomainms:
  445             if (!dns_name_issubdomain(name, rule->name)) {
  446                 continue;
  447             }
  448             if (dst_gssapi_identitymatchesrealmms(
  449                     signer, NULL, rule->identity, false)) {
  450                 break;
  451             }
  452             continue;
  453         case dns_ssumatchtype_tcpself:
  454             tcpself = dns_fixedname_initname(&fixed);
  455             reverse_from_address(tcpself, addr);
  456             if (dns_name_iswildcard(rule->identity)) {
  457                 if (!dns_name_matcheswildcard(tcpself,
  458                                   rule->identity)) {
  459                     continue;
  460                 }
  461             } else {
  462                 if (!dns_name_equal(tcpself, rule->identity)) {
  463                     continue;
  464                 }
  465             }
  466             if (!dns_name_equal(tcpself, name)) {
  467                 continue;
  468             }
  469             break;
  470         case dns_ssumatchtype_6to4self:
  471             stfself = dns_fixedname_initname(&fixed);
  472             stf_from_address(stfself, addr);
  473             if (dns_name_iswildcard(rule->identity)) {
  474                 if (!dns_name_matcheswildcard(stfself,
  475                                   rule->identity)) {
  476                     continue;
  477                 }
  478             } else {
  479                 if (!dns_name_equal(stfself, rule->identity)) {
  480                     continue;
  481                 }
  482             }
  483             if (!dns_name_equal(stfself, name)) {
  484                 continue;
  485             }
  486             break;
  487         case dns_ssumatchtype_external:
  488             if (!dns_ssu_external_match(rule->identity, signer,
  489                             name, addr, type, key,
  490                             table->mctx))
  491             {
  492                 continue;
  493             }
  494             break;
  495         case dns_ssumatchtype_dlz:
  496             if (!dns_dlz_ssumatch(table->dlzdatabase, signer, name,
  497                           addr, type, key)) {
  498                 continue;
  499             }
  500             break;
  501         }
  502 
  503         if (rule->ntypes == 0) {
  504             /*
  505              * If this is a DLZ rule, then the DLZ ssu
  506              * checks will have already checked
  507              * the type.
  508              */
  509             if (rule->matchtype != dns_ssumatchtype_dlz &&
  510                 !isusertype(type)) {
  511                 continue;
  512             }
  513         } else {
  514             for (i = 0; i < rule->ntypes; i++) {
  515                 if (rule->types[i].type == dns_rdatatype_any ||
  516                     rule->types[i].type == type) {
  517                     break;
  518                 }
  519             }
  520             if (i == rule->ntypes) {
  521                 continue;
  522             }
  523         }
  524         if (rule->grant && rulep != NULL) {
  525             *rulep = rule;
  526         }
  527         return (rule->grant);
  528     }
  529 
  530     return (false);
  531 }
  532 
  533 bool
  534 dns_ssurule_isgrant(const dns_ssurule_t *rule) {
  535     REQUIRE(VALID_SSURULE(rule));
  536     return (rule->grant);
  537 }
  538 
  539 dns_name_t *
  540 dns_ssurule_identity(const dns_ssurule_t *rule) {
  541     REQUIRE(VALID_SSURULE(rule));
  542     return (rule->identity);
  543 }
  544 
  545 unsigned int
  546 dns_ssurule_matchtype(const dns_ssurule_t *rule) {
  547     REQUIRE(VALID_SSURULE(rule));
  548     return (rule->matchtype);
  549 }
  550 
  551 dns_name_t *
  552 dns_ssurule_name(const dns_ssurule_t *rule) {
  553     REQUIRE(VALID_SSURULE(rule));
  554     return (rule->name);
  555 }
  556 
  557 unsigned int
  558 dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types) {
  559     REQUIRE(VALID_SSURULE(rule));
  560     REQUIRE(types != NULL && *types != NULL);
  561     *types = rule->types;
  562     return (rule->ntypes);
  563 }
  564 
  565 unsigned int
  566 dns_ssurule_max(const dns_ssurule_t *rule, dns_rdatatype_t type) {
  567     unsigned int i;
  568     unsigned int max = 0;
  569 
  570     REQUIRE(VALID_SSURULE(rule));
  571 
  572     for (i = 0; i < rule->ntypes; i++) {
  573         if (rule->types[i].type == dns_rdatatype_any) {
  574             max = rule->types[i].max;
  575         }
  576         if (rule->types[i].type == type) {
  577             return (rule->types[i].max);
  578         }
  579     }
  580     return (max);
  581 }
  582 
  583 isc_result_t
  584 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
  585     REQUIRE(VALID_SSUTABLE(table));
  586     REQUIRE(rule != NULL && *rule == NULL);
  587     *rule = ISC_LIST_HEAD(table->rules);
  588     return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
  589 }
  590 
  591 isc_result_t
  592 dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
  593     REQUIRE(VALID_SSURULE(rule));
  594     REQUIRE(nextrule != NULL && *nextrule == NULL);
  595     *nextrule = ISC_LIST_NEXT(rule, link);
  596     return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
  597 }
  598 
  599 /*
  600  * Create a specialised SSU table that points at an external DLZ database
  601  */
  602 isc_result_t
  603 dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
  604                dns_dlzdb_t *dlzdatabase) {
  605     isc_result_t result;
  606     dns_ssurule_t *rule;
  607     dns_ssutable_t *table = NULL;
  608 
  609     REQUIRE(tablep != NULL && *tablep == NULL);
  610 
  611     result = dns_ssutable_create(mctx, &table);
  612     if (result != ISC_R_SUCCESS) {
  613         return (result);
  614     }
  615 
  616     table->dlzdatabase = dlzdatabase;
  617 
  618     rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
  619 
  620     rule->identity = NULL;
  621     rule->name = NULL;
  622     rule->grant = true;
  623     rule->matchtype = dns_ssumatchtype_dlz;
  624     rule->ntypes = 0;
  625     rule->types = NULL;
  626     rule->magic = SSURULEMAGIC;
  627 
  628     ISC_LIST_INITANDAPPEND(table->rules, rule, link);
  629     *tablep = table;
  630     return (ISC_R_SUCCESS);
  631 }
  632 
  633 isc_result_t
  634 dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) {
  635     REQUIRE(str != NULL);
  636     REQUIRE(mtype != NULL);
  637 
  638     if (strcasecmp(str, "name") == 0) {
  639         *mtype = dns_ssumatchtype_name;
  640     } else if (strcasecmp(str, "subdomain") == 0) {
  641         *mtype = dns_ssumatchtype_subdomain;
  642     } else if (strcasecmp(str, "wildcard") == 0) {
  643         *mtype = dns_ssumatchtype_wildcard;
  644     } else if (strcasecmp(str, "self") == 0) {
  645         *mtype = dns_ssumatchtype_self;
  646     } else if (strcasecmp(str, "selfsub") == 0) {
  647         *mtype = dns_ssumatchtype_selfsub;
  648     } else if (strcasecmp(str, "selfwild") == 0) {
  649         *mtype = dns_ssumatchtype_selfwild;
  650     } else if (strcasecmp(str, "ms-self") == 0) {
  651         *mtype = dns_ssumatchtype_selfms;
  652     } else if (strcasecmp(str, "ms-selfsub") == 0) {
  653         *mtype = dns_ssumatchtype_selfsubms;
  654     } else if (strcasecmp(str, "krb5-self") == 0) {
  655         *mtype = dns_ssumatchtype_selfkrb5;
  656     } else if (strcasecmp(str, "krb5-selfsub") == 0) {
  657         *mtype = dns_ssumatchtype_selfsubkrb5;
  658     } else if (strcasecmp(str, "ms-subdomain") == 0) {
  659         *mtype = dns_ssumatchtype_subdomainms;
  660     } else if (strcasecmp(str, "krb5-subdomain") == 0) {
  661         *mtype = dns_ssumatchtype_subdomainkrb5;
  662     } else if (strcasecmp(str, "tcp-self") == 0) {
  663         *mtype = dns_ssumatchtype_tcpself;
  664     } else if (strcasecmp(str, "6to4-self") == 0) {
  665         *mtype = dns_ssumatchtype_6to4self;
  666     } else if (strcasecmp(str, "zonesub") == 0) {
  667         *mtype = dns_ssumatchtype_subdomain;
  668     } else if (strcasecmp(str, "external") == 0) {
  669         *mtype = dns_ssumatchtype_external;
  670     } else {
  671         return (ISC_R_NOTFOUND);
  672     }
  673     return (ISC_R_SUCCESS);
  674 }