]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add {krb5,ms}-subdomain-self-rhs update policy rules
authorMark Andrews <marka@isc.org>
Thu, 23 Aug 2018 23:19:38 +0000 (09:19 +1000)
committerMark Andrews <marka@isc.org>
Fri, 15 Oct 2021 00:18:41 +0000 (11:18 +1100)
The new rules compare the target name in PTR and SRV records against
the machine name embedded in the kerberos principal.  This can be
used to further restrict what PTR and SRV records can be added or
deleted via dynamic updates if desired.

bin/named/named.conf.rst
doc/man/named.conf.5in
doc/misc/master.zoneopt
doc/misc/master.zoneopt.rst
doc/misc/options
doc/misc/options.active
lib/bind9/check.c
lib/dns/include/dns/ssu.h
lib/dns/ssu.c
lib/isccfg/namedconf.c
lib/ns/update.c

index 7274c2044abf6a53b98b1c26892dc5e5a1f8da36..3793cfe123acee1eb0b871b5129d42afe87b6050 100644 (file)
@@ -991,7 +991,8 @@ VIEW
                update-check-ksk boolean;
                update-policy ( local | { ( deny | grant ) string (
                    6to4-self | external | krb5-self | krb5-selfsub |
-                   krb5-subdomain | ms-self | ms-selfsub | ms-subdomain |
+                   krb5-subdomain | krb5-subdomain-self-rhs | ms-self |
+                   ms-selfsub | ms-subdomain | ms-subdomain-self-rhs |
                    name | self | selfsub | selfwild | subdomain | tcp-self
                    | wildcard | zonesub ) [ string ] rrtypelist; ... };
                use-alt-transfer-source boolean;
@@ -1106,9 +1107,10 @@ ZONE
            stub );
        update-check-ksk boolean;
        update-policy ( local | { ( deny | grant ) string ( 6to4-self |
-           external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self
-           | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild
-           | subdomain | tcp-self | wildcard | zonesub ) [ string ]
+           external | krb5-self | krb5-selfsub | krb5-subdomain |
+           krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain |
+           ms-subdomain-self-rhs | name | self | selfsub | selfwild |
+           subdomain | tcp-self | wildcard | zonesub ) [ string ]
            rrtypelist; ... };
        use-alt-transfer-source boolean;
        zero-no-soa-ttl boolean;
index 30d73bab2f80dd0ddb2b3374f7b5b062413478a9..b5bcfcccf86a3df9863a5506af31dcd5e80eaadd 100644 (file)
@@ -1094,7 +1094,8 @@ view string [ class ] {
               update\-check\-ksk boolean;
               update\-policy ( local | { ( deny | grant ) string (
                   6to4\-self | external | krb5\-self | krb5\-selfsub |
-                  krb5\-subdomain | ms\-self | ms\-selfsub | ms\-subdomain |
+                  krb5\-subdomain | krb5\-subdomain\-self\-rhs | ms\-self |
+                  ms\-selfsub | ms\-subdomain | ms\-subdomain\-self\-rhs |
                   name | self | selfsub | selfwild | subdomain | tcp\-self
                   | wildcard | zonesub ) [ string ] rrtypelist; ... };
               use\-alt\-transfer\-source boolean;
@@ -1213,9 +1214,10 @@ zone string [ class ] {
           stub );
       update\-check\-ksk boolean;
       update\-policy ( local | { ( deny | grant ) string ( 6to4\-self |
-          external | krb5\-self | krb5\-selfsub | krb5\-subdomain | ms\-self
-          | ms\-selfsub | ms\-subdomain | name | self | selfsub | selfwild
-          | subdomain | tcp\-self | wildcard | zonesub ) [ string ]
+          external | krb5\-self | krb5\-selfsub | krb5\-subdomain |
+          krb5\-subdomain\-self\-rhs | ms\-self | ms\-selfsub | ms\-subdomain |
+          ms\-subdomain\-self\-rhs | name | self | selfsub | selfwild |
+          subdomain | tcp\-self | wildcard | zonesub ) [ string ]
           rrtypelist; ... };
       use\-alt\-transfer\-source boolean;
       zero\-no\-soa\-ttl boolean;
index 027972a77096afdfae43064b9753e4c6b6c49355..e51eee9bcc9bce256e075c960574ffcee15657ef 100644 (file)
@@ -55,7 +55,7 @@ zone <string> [ <class> ] {
        sig-signing-type <integer>;
        sig-validity-interval <integer> [ <integer> ];
        update-check-ksk <boolean>;
-       update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
+       update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
        zero-no-soa-ttl <boolean>;
        zone-statistics ( full | terse | none | <boolean> );
 };
index e73005dc86336ab6449c0705ff058eb321d387b2..985e2b404ffeca1ead9b13b96d94692f5bfc873d 100644 (file)
@@ -57,7 +57,7 @@
        sig-signing-type <integer>;
        sig-validity-interval <integer> [ <integer> ];
        update-check-ksk <boolean>;
-       update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
+       update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
        zero-no-soa-ttl <boolean>;
        zone-statistics ( full | terse | none | <boolean> );
   };
index 06fec355affcb9c391267eb62a9f52d2cbaf8b67..fb9db8c4c6d44cc7acfa51aba4a29192b4f2c1ae 100644 (file)
@@ -873,7 +873,8 @@ view <string> [ <class> ] {
                 update-check-ksk <boolean>;
                 update-policy ( local | { ( deny | grant ) <string> (
                     6to4-self | external | krb5-self | krb5-selfsub |
-                    krb5-subdomain | ms-self | ms-selfsub | ms-subdomain |
+                    krb5-subdomain | krb5-subdomain-self-rhs | ms-self |
+                    ms-selfsub | ms-subdomain | ms-subdomain-self-rhs |
                     name | self | selfsub | selfwild | subdomain | tcp-self
                     | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
                 use-alt-transfer-source <boolean>;
@@ -984,9 +985,10 @@ zone <string> [ <class> ] {
             stub );
         update-check-ksk <boolean>;
         update-policy ( local | { ( deny | grant ) <string> ( 6to4-self |
-            external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self
-            | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild
-            | subdomain | tcp-self | wildcard | zonesub ) [ <string> ]
+            external | krb5-self | krb5-selfsub | krb5-subdomain |
+            krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain |
+            ms-subdomain-self-rhs | name | self | selfsub | selfwild |
+            subdomain | tcp-self | wildcard | zonesub ) [ <string> ]
             <rrtypelist>; ... };
         use-alt-transfer-source <boolean>;
         zero-no-soa-ttl <boolean>;
index 226e77da17fabb75ff135115e5ccb731269216c5..c8d71c55328a603ebfc5621d5d1cf8ba05d5073b 100644 (file)
@@ -867,7 +867,8 @@ view <string> [ <class> ] {
                 update-check-ksk <boolean>;
                 update-policy ( local | { ( deny | grant ) <string> (
                     6to4-self | external | krb5-self | krb5-selfsub |
-                    krb5-subdomain | ms-self | ms-selfsub | ms-subdomain |
+                    krb5-subdomain | krb5-subdomain-self-rhs | ms-self |
+                    ms-selfsub | ms-subdomain | ms-subdomain-self-rhs |
                     name | self | selfsub | selfwild | subdomain | tcp-self
                     | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
                 use-alt-transfer-source <boolean>;
@@ -977,9 +978,10 @@ zone <string> [ <class> ] {
             stub );
         update-check-ksk <boolean>;
         update-policy ( local | { ( deny | grant ) <string> ( 6to4-self |
-            external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self
-            | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild
-            | subdomain | tcp-self | wildcard | zonesub ) [ <string> ]
+            external | krb5-self | krb5-selfsub | krb5-subdomain |
+            krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain |
+            ms-subdomain-self-rhs | name | self | selfsub | selfwild |
+            subdomain | tcp-self | wildcard | zonesub ) [ <string> ]
             <rrtypelist>; ... };
         use-alt-transfer-source <boolean>;
         zero-no-soa-ttl <boolean>;
index 7e2b2ac2d063a5c9e0bfea4b5ff09e933f5dc73b..d34f7774bd56a79535fe5b7ebd1a6e9dad26e5f1 100644 (file)
@@ -2573,7 +2573,9 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
                case dns_ssumatchtype_name:
                case dns_ssumatchtype_subdomain: /* also zonesub */
                case dns_ssumatchtype_subdomainms:
+               case dns_ssumatchtype_subdomainselfmsrhs:
                case dns_ssumatchtype_subdomainkrb5:
+               case dns_ssumatchtype_subdomainselfkrb5rhs:
                case dns_ssumatchtype_wildcard:
                case dns_ssumatchtype_external:
                case dns_ssumatchtype_local:
index 6b3b8ee7b86b5f0ae9f1e2edb7a5a174c01aa284..caa498e811d36b38a216ae558708046b6d6bcef1 100644 (file)
@@ -41,9 +41,11 @@ typedef enum {
        dns_ssumatchtype_local = 13,
        dns_ssumatchtype_selfsubms = 14,
        dns_ssumatchtype_selfsubkrb5 = 15,
-       dns_ssumatchtype_max = 15, /* max value */
+       dns_ssumatchtype_subdomainselfkrb5rhs = 16,
+       dns_ssumatchtype_subdomainselfmsrhs = 17,
+       dns_ssumatchtype_max = 17, /* max value */
 
-       dns_ssumatchtype_dlz = 16 /* intentionally higher than _max */
+       dns_ssumatchtype_dlz = 18 /* intentionally higher than _max */
 } dns_ssumatchtype_t;
 
 typedef struct dns_ssuruletype {
@@ -140,7 +142,8 @@ bool
 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        const dns_name_t *name, const isc_netaddr_t *addr,
                        bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type,
-                       const dst_key_t *key, const dns_ssurule_t **rulep);
+                       const dns_name_t *target, const dst_key_t *key,
+                       const dns_ssurule_t **rulep);
 /*%<
  *     Checks that the attempted update of (name, type) is allowed according
  *     to the rules specified in the simple-secure-update rule table.  If
index 68558be0a9bcaa1c6fee7e611b46b99d78dcc65b..0c41314c3a0e5449d7d4136c25ddb9e500f455a8 100644 (file)
@@ -280,12 +280,14 @@ bool
 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        const dns_name_t *name, const isc_netaddr_t *addr,
                        bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type,
-                       const dst_key_t *key, const dns_ssurule_t **rulep) {
+                       const dns_name_t *target, const dst_key_t *key,
+                       const dns_ssurule_t **rulep) {
        dns_fixedname_t fixed;
        dns_name_t *stfself;
        dns_name_t *tcpself;
        dns_name_t *wildcard;
        dns_ssurule_t *rule;
+       const dns_name_t *tname;
        int match;
        isc_result_t result;
        unsigned int i;
@@ -303,13 +305,13 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
             rule = ISC_LIST_NEXT(rule, link))
        {
                switch (rule->matchtype) {
-               case dns_ssumatchtype_name:
                case dns_ssumatchtype_local:
-               case dns_ssumatchtype_subdomain:
-               case dns_ssumatchtype_wildcard:
+               case dns_ssumatchtype_name:
                case dns_ssumatchtype_self:
                case dns_ssumatchtype_selfsub:
                case dns_ssumatchtype_selfwild:
+               case dns_ssumatchtype_subdomain:
+               case dns_ssumatchtype_wildcard:
                        if (signer == NULL) {
                                continue;
                        }
@@ -330,6 +332,8 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                case dns_ssumatchtype_selfsubms:
                case dns_ssumatchtype_subdomainkrb5:
                case dns_ssumatchtype_subdomainms:
+               case dns_ssumatchtype_subdomainselfkrb5rhs:
+               case dns_ssumatchtype_subdomainselfmsrhs:
                        if (signer == NULL) {
                                continue;
                        }
@@ -430,20 +434,48 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        }
                        continue;
                case dns_ssumatchtype_subdomainkrb5:
+               case dns_ssumatchtype_subdomainselfkrb5rhs:
                        if (!dns_name_issubdomain(name, rule->name)) {
                                continue;
                        }
+                       tname = NULL;
+                       switch (rule->matchtype) {
+                       case dns_ssumatchtype_subdomainselfkrb5rhs:
+                               if (type == dns_rdatatype_ptr) {
+                                       tname = target;
+                               }
+                               if (type == dns_rdatatype_srv) {
+                                       tname = target;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
                        if (dst_gssapi_identitymatchesrealmkrb5(
-                                   signer, NULL, rule->identity, false)) {
+                                   signer, tname, rule->identity, false)) {
                                break;
                        }
                        continue;
                case dns_ssumatchtype_subdomainms:
+               case dns_ssumatchtype_subdomainselfmsrhs:
                        if (!dns_name_issubdomain(name, rule->name)) {
                                continue;
                        }
+                       tname = NULL;
+                       switch (rule->matchtype) {
+                       case dns_ssumatchtype_subdomainselfmsrhs:
+                               if (type == dns_rdatatype_ptr) {
+                                       tname = target;
+                               }
+                               if (type == dns_rdatatype_srv) {
+                                       tname = target;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
                        if (dst_gssapi_identitymatchesrealmms(
-                                   signer, NULL, rule->identity, false)) {
+                                   signer, tname, rule->identity, false)) {
                                break;
                        }
                        continue;
@@ -500,8 +532,7 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                if (rule->ntypes == 0) {
                        /*
                         * If this is a DLZ rule, then the DLZ ssu
-                        * checks will have already checked
-                        * the type.
+                        * checks will have already checked the type.
                         */
                        if (rule->matchtype != dns_ssumatchtype_dlz &&
                            !isusertype(type)) {
@@ -649,8 +680,12 @@ dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) {
                *mtype = dns_ssumatchtype_selfsubkrb5;
        } else if (strcasecmp(str, "ms-subdomain") == 0) {
                *mtype = dns_ssumatchtype_subdomainms;
+       } else if (strcasecmp(str, "ms-subdomain-self-rhs") == 0) {
+               *mtype = dns_ssumatchtype_subdomainselfmsrhs;
        } else if (strcasecmp(str, "krb5-subdomain") == 0) {
                *mtype = dns_ssumatchtype_subdomainkrb5;
+       } else if (strcasecmp(str, "krb5-subdomain-self-rhs") == 0) {
+               *mtype = dns_ssumatchtype_subdomainselfkrb5rhs;
        } else if (strcasecmp(str, "tcp-self") == 0) {
                *mtype = dns_ssumatchtype_tcpself;
        } else if (strcasecmp(str, "6to4-self") == 0) {
index ecf346a0549cd7184e0ac6b07acecdc69b035748..fcbd929106234a532a5c762bef3979603dd91c7a 100644 (file)
@@ -320,9 +320,11 @@ static const char *matchtype_enums[] = { "6to4-self",
                                         "krb5-self",
                                         "krb5-selfsub",
                                         "krb5-subdomain",
+                                        "krb5-subdomain-self-rhs",
                                         "ms-self",
                                         "ms-selfsub",
                                         "ms-subdomain",
+                                        "ms-subdomain-self-rhs",
                                         "name",
                                         "self",
                                         "selfsub",
index 2ae87af3b176c56ebaecb5f7560b8ca7fa2eaf9f..f268cde0d77629668b87f407436b3de16403529a 100644 (file)
@@ -918,9 +918,8 @@ typedef struct {
 
 static isc_result_t
 ssu_checkrule(void *data, dns_rdataset_t *rrset) {
-       const dns_ssurule_t *rule = NULL;
        ssu_check_t *ssuinfo = data;
-       bool rule_ok;
+       bool rule_ok = false;
 
        /*
         * If we're deleting all records, it's ok to delete RRSIG and NSEC even
@@ -931,10 +930,58 @@ ssu_checkrule(void *data, dns_rdataset_t *rrset) {
                return (ISC_R_SUCCESS);
        }
 
-       rule_ok = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
-                                         ssuinfo->name, ssuinfo->addr,
-                                         ssuinfo->tcp, ssuinfo->aclenv,
-                                         rrset->type, ssuinfo->key, &rule);
+       /*
+        * krb5-subdomain-self-rhs and ms-subdomain-self-rhs need
+        * to check the PTR and SRV target names so extract them
+        * from the resource records.
+        */
+       if (rrset->rdclass == dns_rdataclass_in &&
+           (rrset->type == dns_rdatatype_srv ||
+            rrset->type == dns_rdatatype_ptr))
+       {
+               dns_name_t *target = NULL;
+               dns_rdata_ptr_t ptr;
+               dns_rdata_in_srv_t srv;
+               dns_rdataset_t rdataset;
+               isc_result_t result;
+
+               dns_rdataset_init(&rdataset);
+               dns_rdataset_clone(rrset, &rdataset);
+
+               for (result = dns_rdataset_first(&rdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&rdataset))
+               {
+                       dns_rdata_t rdata = DNS_RDATA_INIT;
+                       dns_rdataset_current(&rdataset, &rdata);
+                       if (rrset->type == dns_rdatatype_ptr) {
+                               result = dns_rdata_tostruct(&rdata, &ptr, NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                               target = &ptr.ptr;
+                       }
+                       if (rrset->type == dns_rdatatype_srv) {
+                               result = dns_rdata_tostruct(&rdata, &srv, NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                               target = &srv.target;
+                       }
+                       rule_ok = dns_ssutable_checkrules(
+                               ssuinfo->table, ssuinfo->signer, ssuinfo->name,
+                               ssuinfo->addr, ssuinfo->tcp, ssuinfo->aclenv,
+                               rrset->type, target, ssuinfo->key, NULL);
+                       if (!rule_ok) {
+                               break;
+                       }
+               }
+               if (result != ISC_R_NOMORE) {
+                       rule_ok = false;
+               }
+               dns_rdataset_disassociate(&rdataset);
+       } else {
+               rule_ok = dns_ssutable_checkrules(
+                       ssuinfo->table, ssuinfo->signer, ssuinfo->name,
+                       ssuinfo->addr, ssuinfo->tcp, ssuinfo->aclenv,
+                       rrset->type, NULL, ssuinfo->key, NULL);
+       }
        return (rule_ok ? ISC_R_SUCCESS : ISC_R_FAILURE);
 }
 
@@ -956,6 +1003,33 @@ ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
        return (result == ISC_R_SUCCESS);
 }
 
+static isc_result_t
+ssu_checkrr(void *data, rr_t *rr) {
+       isc_result_t result;
+       ssu_check_t *ssuinfo = data;
+       dns_name_t *target = NULL;
+       dns_rdata_ptr_t ptr;
+       dns_rdata_in_srv_t srv;
+       bool answer;
+
+       if (rr->rdata.type == dns_rdatatype_ptr) {
+               result = dns_rdata_tostruct(&rr->rdata, &ptr, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               target = &ptr.ptr;
+       }
+       if (rr->rdata.type == dns_rdatatype_srv) {
+               result = dns_rdata_tostruct(&rr->rdata, &srv, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               target = &srv.target;
+       }
+
+       answer = dns_ssutable_checkrules(
+               ssuinfo->table, ssuinfo->signer, ssuinfo->name, ssuinfo->addr,
+               ssuinfo->tcp, ssuinfo->aclenv, rr->rdata.type, target,
+               ssuinfo->key, NULL);
+       return (answer ? ISC_R_SUCCESS : ISC_R_FAILURE);
+}
+
 /**************************************************************************/
 /*
  * Checking of "RRset exists (value dependent)" prerequisites.
@@ -2848,18 +2922,77 @@ update_action(isc_task_t *task, isc_event_t *event) {
 
                if (ssutable != NULL) {
                        isc_netaddr_t netaddr;
+                       dns_name_t *target = NULL;
                        dst_key_t *tsigkey = NULL;
+                       dns_rdata_ptr_t ptr;
+                       dns_rdata_in_srv_t srv;
+
                        isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
 
                        if (client->message->tsigkey != NULL) {
                                tsigkey = client->message->tsigkey->key;
                        }
 
-                       if (rdata.type != dns_rdatatype_any) {
+                       if ((update_class == dns_rdataclass_in ||
+                            update_class == dns_rdataclass_none) &&
+                           rdata.type == dns_rdatatype_ptr)
+                       {
+                               result = dns_rdata_tostruct(&rdata, &ptr, NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                               target = &ptr.ptr;
+                       }
+
+                       if ((update_class == dns_rdataclass_in ||
+                            update_class == dns_rdataclass_none) &&
+                           rdata.type == dns_rdatatype_srv)
+                       {
+                               result = dns_rdata_tostruct(&rdata, &srv, NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                               target = &srv.target;
+                       }
+
+                       if (update_class == dns_rdataclass_any &&
+                           zoneclass == dns_rdataclass_in &&
+                           (rdata.type == dns_rdatatype_ptr ||
+                            rdata.type == dns_rdatatype_srv))
+                       {
+                               ssu_check_t ssuinfo;
+
+                               ssuinfo.name = name;
+                               ssuinfo.table = ssutable;
+                               ssuinfo.signer = client->signer;
+                               ssuinfo.addr = &netaddr;
+                               ssuinfo.aclenv = env;
+                               ssuinfo.tcp = TCPCLIENT(client);
+                               ssuinfo.key = tsigkey;
+
+                               result = foreach_rr(db, ver, name, rdata.type,
+                                                   dns_rdatatype_none,
+                                                   ssu_checkrr, &ssuinfo);
+                               if (result != ISC_R_SUCCESS) {
+                                       FAILC(DNS_R_REFUSED,
+                                             "rejected by secure update");
+                               }
+                       } else if (target != NULL &&
+                                  update_class == dns_rdataclass_none) {
+                               bool flag;
+                               CHECK(rr_exists(db, ver, name, &rdata, &flag));
+                               if (flag &&
+                                   !dns_ssutable_checkrules(
+                                           ssutable, client->signer, name,
+                                           &netaddr, TCPCLIENT(client), env,
+                                           rdata.type, target, tsigkey,
+                                           &rules[rule]))
+                               {
+                                       FAILC(DNS_R_REFUSED,
+                                             "rejected by secure update");
+                               }
+                       } else if (rdata.type != dns_rdatatype_any) {
                                if (!dns_ssutable_checkrules(
                                            ssutable, client->signer, name,
                                            &netaddr, TCPCLIENT(client), env,
-                                           rdata.type, tsigkey, &rules[rule]))
+                                           rdata.type, target, tsigkey,
+                                           &rules[rule]))
                                {
                                        FAILC(DNS_R_REFUSED, "rejected by "
                                                             "secure update");