"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/ssu.c" (7 Sep 2020, 18810 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


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