s4 dns: Improve logging of delegated dns updates
[nivanova/samba-autobuild/.git] / source4 / dns_server / dns_update.c
index 3473a70f55290c396a5b2822688e6d9539e32c44..aa80b52bdd70847ece89839e00dd4b5f9994daf2 100644 (file)
 #include "librpc/gen_ndr/ndr_dnsp.h"
 #include <ldb.h>
 #include "param/param.h"
+#include "param/loadparm.h"
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "smbd/service_task.h"
 #include "dns_server/dns_server.h"
-#include "dns_server/dns_update.h"
+#include "auth/auth.h"
 
 static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                             const struct dns_res_rec *rrec,
@@ -381,7 +382,8 @@ done:
 static WERROR handle_one_update(struct dns_server *dns,
                                TALLOC_CTX *mem_ctx,
                                const struct dns_name_question *zone,
-                               const struct dns_res_rec *update)
+                               const struct dns_res_rec *update,
+                               const struct dns_server_tkey *tkey)
 {
        struct dnsp_DnssrvRpcRecord *recs = NULL;
        uint16_t rcount = 0;
@@ -389,6 +391,7 @@ static WERROR handle_one_update(struct dns_server *dns,
        uint16_t i;
        WERROR werror;
        bool needs_add = false;
+       uint32_t access_mask = 0;
 
        DEBUG(2, ("Looking at record: \n"));
        if (DEBUGLVL(2)) {
@@ -397,21 +400,13 @@ static WERROR handle_one_update(struct dns_server *dns,
 
        switch (update->rr_type) {
        case DNS_QTYPE_A:
-               break;
        case DNS_QTYPE_NS:
-               break;
        case DNS_QTYPE_CNAME:
-               break;
        case DNS_QTYPE_SOA:
-               break;
        case DNS_QTYPE_PTR:
-               break;
        case DNS_QTYPE_MX:
-               break;
        case DNS_QTYPE_AAAA:
-               break;
        case DNS_QTYPE_SRV:
-               break;
        case DNS_QTYPE_TXT:
                break;
        default:
@@ -429,9 +424,24 @@ static WERROR handle_one_update(struct dns_server *dns,
                rcount = 0;
                needs_add = true;
                werror = WERR_OK;
+               access_mask = SEC_ADS_CREATE_CHILD;
        }
        W_ERROR_NOT_OK_RETURN(werror);
 
+       access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE;
+
+       if (tkey != NULL) {
+               int ldb_ret;
+               ldb_ret = dsdb_check_access_on_dn(dns->samdb, mem_ctx, dn,
+                                                 tkey->session_info->security_token,
+                                                 access_mask, NULL);
+               if (ldb_ret != LDB_SUCCESS) {
+                       DEBUG(5, ("Disallowing update: %s\n", ldb_strerror(ldb_ret)));
+                       return DNS_ERR(REFUSED);
+               }
+               DEBUG(5, ("Allowing signed update\n"));
+       }
+
        if (update->rr_class == zone->question_class) {
                if (update->rr_type == DNS_QTYPE_CNAME) {
                        /*
@@ -440,7 +450,7 @@ static WERROR handle_one_update(struct dns_server *dns,
                         */
                        for (i = 0; i < rcount; i++) {
                                if (recs[i].wType != DNS_TYPE_CNAME) {
-                                       DEBUG(0, ("Skipping update\n"));
+                                       DEBUG(5, ("Skipping update\n"));
                                        return WERR_OK;
                                }
                                break;
@@ -471,7 +481,7 @@ static WERROR handle_one_update(struct dns_server *dns,
                         */
                        for (i = 0; i < rcount; i++) {
                                if (recs[i].wType == DNS_TYPE_CNAME) {
-                                       DEBUG(0, ("Skipping update\n"));
+                                       DEBUG(5, ("Skipping update\n"));
                                        return WERR_OK;
                                }
                        }
@@ -495,7 +505,7 @@ static WERROR handle_one_update(struct dns_server *dns,
                                         * logic for RFC2136
                                         */
                                        if (n <= o) {
-                                               DEBUG(0, ("Skipping update\n"));
+                                               DEBUG(5, ("Skipping update\n"));
                                                return WERR_OK;
                                        }
                                        found = true;
@@ -503,7 +513,7 @@ static WERROR handle_one_update(struct dns_server *dns,
                                }
                        }
                        if (!found) {
-                               DEBUG(0, ("Skipping update\n"));
+                               DEBUG(5, ("Skipping update\n"));
                                return WERR_OK;
                        }
 
@@ -645,7 +655,8 @@ static WERROR handle_updates(struct dns_server *dns,
                             TALLOC_CTX *mem_ctx,
                             const struct dns_name_question *zone,
                             const struct dns_res_rec *prereqs, uint16_t pcount,
-                            struct dns_res_rec *updates, uint16_t upd_count)
+                            struct dns_res_rec *updates, uint16_t upd_count,
+                            struct dns_server_tkey *tkey)
 {
        struct ldb_dn *zone_dn = NULL;
        WERROR werror = WERR_OK;
@@ -664,11 +675,11 @@ static WERROR handle_updates(struct dns_server *dns,
        werror = check_prerequisites(dns, tmp_ctx, zone, prereqs, pcount);
        W_ERROR_NOT_OK_GOTO(werror, failed);
 
-       DEBUG(0, ("update count is %u\n", upd_count));
+       DEBUG(1, ("update count is %u\n", upd_count));
 
        for (ri = 0; ri < upd_count; ri++) {
                werror = handle_one_update(dns, tmp_ctx, zone,
-                                          &updates[ri]);
+                                          &updates[ri], tkey);
                W_ERROR_NOT_OK_GOTO(werror, failed);
        }
 
@@ -683,6 +694,35 @@ failed:
 
 }
 
+static WERROR dns_update_allowed(struct dns_server *dns,
+                                struct dns_request_state *state,
+                                struct dns_server_tkey **tkey)
+{
+       if (lpcfg_allow_dns_updates(dns->task->lp_ctx) == DNS_UPDATE_ON) {
+               DEBUG(2, ("All updates allowed.\n"));
+               return WERR_OK;
+       }
+
+       if (lpcfg_allow_dns_updates(dns->task->lp_ctx) == DNS_UPDATE_OFF) {
+               DEBUG(2, ("Updates disabled.\n"));
+               return DNS_ERR(REFUSED);
+       }
+
+       if (state->authenticated == false ) {
+               DEBUG(2, ("Update not allowed for unsigned packet.\n"));
+               return DNS_ERR(REFUSED);
+       }
+
+        *tkey = dns_find_tkey(dns->tkeys, state->key_name);
+       if (*tkey == NULL) {
+               DEBUG(0, ("Authenticated, but key not found. Something is wrong.\n"));
+               return DNS_ERR(REFUSED);
+       }
+
+       return WERR_OK;
+}
+
+
 WERROR dns_server_process_update(struct dns_server *dns,
                                 struct dns_request_state *state,
                                 TALLOC_CTX *mem_ctx,
@@ -695,6 +735,7 @@ WERROR dns_server_process_update(struct dns_server *dns,
        const struct dns_server_zone *z;
        size_t host_part_len = 0;
        WERROR werror = DNS_ERR(NOT_IMPLEMENTED);
+       struct dns_server_tkey *tkey = NULL;
 
        if (in->qdcount != 1) {
                return DNS_ERR(FORMAT_ERROR);
@@ -723,13 +764,13 @@ WERROR dns_server_process_update(struct dns_server *dns,
        }
 
        if (z == NULL) {
-               DEBUG(0, ("We're not authorative for this zone\n"));
+               DEBUG(1, ("We're not authoritative for this zone\n"));
                return DNS_ERR(NOTAUTH);
        }
 
        if (host_part_len != 0) {
                /* TODO: We need to delegate this one */
-               DEBUG(0, ("Would have to delegate zones.\n"));
+               DEBUG(1, ("Would have to delegate zone '%s'.\n", zone->name));
                return DNS_ERR(NOT_IMPLEMENTED);
        }
 
@@ -739,12 +780,9 @@ WERROR dns_server_process_update(struct dns_server *dns,
                                     *prereq_count);
        W_ERROR_NOT_OK_RETURN(werror);
 
-       /* TODO: Check if update is allowed, we probably want "always",
-        * key-based GSSAPI, key-based bind-style TSIG and "never" as
-        * smb.conf options. */
-       if (lpcfg_allow_dns_updates(dns->task->lp_ctx) != DNS_UPDATE_ON) {
-               DEBUG(0, ("Update not allowed.\n"));
-               return DNS_ERR(REFUSED);
+       werror = dns_update_allowed(dns, state, &tkey);
+       if (!W_ERROR_IS_OK(werror)) {
+               return werror;
        }
 
        *update_count = in->nscount;
@@ -752,9 +790,8 @@ WERROR dns_server_process_update(struct dns_server *dns,
        werror = update_prescan(in->questions, *updates, *update_count);
        W_ERROR_NOT_OK_RETURN(werror);
 
-
        werror = handle_updates(dns, mem_ctx, in->questions, *prereqs,
-                               *prereq_count, *updates, *update_count);
+                               *prereq_count, *updates, *update_count, tkey);
        W_ERROR_NOT_OK_RETURN(werror);
 
        return werror;