summaryrefslogtreecommitdiffstats
path: root/source4/dns_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dns_server')
-rw-r--r--source4/dns_server/dns_crypto.c49
-rw-r--r--source4/dns_server/dns_query.c27
-rw-r--r--source4/dns_server/dns_update.c11
-rw-r--r--source4/dns_server/dnsserver_common.c8
4 files changed, 81 insertions, 14 deletions
diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c
index be79a4e..d30e971 100644
--- a/source4/dns_server/dns_crypto.c
+++ b/source4/dns_server/dns_crypto.c
@@ -27,6 +27,7 @@
#include "libcli/util/ntstatus.h"
#include "auth/auth.h"
#include "auth/gensec/gensec.h"
+#include "lib/util/bytearray.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_DNS
@@ -106,7 +107,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
struct dns_server_tkey *tkey = NULL;
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
-
+ const char *algorithm = NULL;
/* Find the first TSIG record in the additional records */
for (i=0; i < packet->arcount; i++) {
@@ -145,7 +146,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
tkey = dns_find_tkey(dns->tkeys, state->tsig->name);
if (tkey == NULL) {
- DBG_DEBUG("dns_find_tkey() => NOTAUTH / DNS_RCODE_BADKEY\n");
+ DBG_DEBUG("dns_find_tkey() => REFUSED / DNS_RCODE_BADKEY\n");
/*
* We must save the name for use in the TSIG error
* response and have no choice here but to save the
@@ -157,10 +158,20 @@ WERROR dns_verify_tsig(struct dns_server *dns,
return WERR_NOT_ENOUGH_MEMORY;
}
state->tsig_error = DNS_RCODE_BADKEY;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
DBG_DEBUG("dns_find_tkey() => found\n");
+ algorithm = state->tsig->rdata.tsig_record.algorithm_name;
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ state->tsig_error = DNS_RCODE_BADKEY;
+ return DNS_ERR(REFUSED);
+ }
+
/*
* Remember the keyname that found an existing tkey, used
* later to fetch the key with dns_find_tkey() when signing
@@ -183,7 +194,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
}
check_rec->rr_class = DNS_QCLASS_ANY;
check_rec->ttl = 0;
- check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm);
+ check_rec->algorithm_name = talloc_strdup(check_rec, algorithm);
if (check_rec->algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
@@ -239,7 +250,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
dump_data_dbgc(DBGC_DNS, 8, buffer, buffer_len);
DBG_NOTICE("Verifying tsig failed: %s\n", nt_errstr(status));
state->tsig_error = DNS_RCODE_BADSIG;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
if (!NT_STATUS_IS_OK(status)) {
@@ -271,11 +282,19 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
size_t mac_size = 0;
+ bool gss_tsig;
if (check_rec == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
+ if (strcmp(tkey->algorithm, "gss-tsig") == 0) {
+ gss_tsig = true;
+ } else {
+ /* gss.microsoft.com */
+ gss_tsig = false;
+ }
+
/* first build and verify check packet */
check_rec->name = talloc_strdup(check_rec, tkey->name);
if (check_rec->name == NULL) {
@@ -315,6 +334,9 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
}
buffer_len = mac_size;
+ if (gss_tsig && mac_size > 0) {
+ buffer_len += 2;
+ }
buffer_len += packet_blob.length;
if (buffer_len < packet_blob.length) {
@@ -335,11 +357,21 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
/*
* RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer
* that we're going to sign:
- * 1. MAC of request (if present)
+ * 1. if MAC of request is present
+ * - 16bit big endian length of MAC of request
+ * - MAC of request
* 2. Outgoing packet
* 3. TSIG record
*/
if (mac_size > 0) {
+ if (gss_tsig) {
+ /*
+ * only gss-tsig not with
+ * gss.microsoft.com
+ */
+ PUSH_BE_U16(p, 0, mac_size);
+ p += 2;
+ }
memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size);
p += mac_size;
}
@@ -372,6 +404,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
.data = NULL,
.length = 0
};
+ const char *algorithm = "gss-tsig";
tsig = talloc_zero(mem_ctx, struct dns_res_rec);
if (tsig == NULL) {
@@ -392,6 +425,8 @@ WERROR dns_sign_tsig(struct dns_server *dns,
if (!W_ERROR_IS_OK(werror)) {
return werror;
}
+
+ algorithm = tkey->algorithm;
}
tsig->name = talloc_strdup(tsig, state->key_name);
@@ -402,7 +437,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
tsig->rr_type = DNS_QTYPE_TSIG;
tsig->ttl = 0;
tsig->length = UINT16_MAX;
- tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig");
+ tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, algorithm);
if (tsig->rdata.tsig_record.algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 181beda..1f46ee0 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -663,8 +663,17 @@ static NTSTATUS create_tkey(struct dns_server *dns,
{
NTSTATUS status;
struct dns_server_tkey_store *store = dns->tkeys;
- struct dns_server_tkey *k = talloc_zero(store, struct dns_server_tkey);
+ struct dns_server_tkey *k = NULL;
+
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ k = talloc_zero(store, struct dns_server_tkey);
if (k == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -790,12 +799,22 @@ static WERROR handle_tkey(struct dns_server *dns,
{
struct dns_res_rec *in_tkey = NULL;
struct dns_res_rec *ret_tkey;
- uint16_t i;
- for (i = 0; i < in->arcount; i++) {
+ /*
+ * TKEY needs to we the last one in
+ * additional or answers
+ */
+ if (in->arcount >= 1) {
+ uint16_t i = in->arcount - 1;
if (in->additional[i].rr_type == DNS_QTYPE_TKEY) {
in_tkey = &in->additional[i];
- break;
+ }
+ } else if (in->nscount >= 1) {
+ /* no lookup */
+ } else if (in->ancount >= 1) {
+ uint16_t i = in->ancount - 1;
+ if (in->answers[i].rr_type == DNS_QTYPE_TKEY) {
+ in_tkey = &in->answers[i];
}
}
diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c
index 4d2ee0b..1285111 100644
--- a/source4/dns_server/dns_update.c
+++ b/source4/dns_server/dns_update.c
@@ -570,6 +570,8 @@ static WERROR handle_one_update(struct dns_server *dns,
W_ERROR_NOT_OK_RETURN(werror);
for (i = first; i < rcount; i++) {
+ struct dnsp_DnssrvRpcRecord orig_rec = recs[i];
+
if (!dns_record_match(&recs[i], &recs[rcount])) {
continue;
}
@@ -583,6 +585,15 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_replace_records(dns, mem_ctx, dn,
needs_add, recs, rcount);
DBG_DEBUG("dns_replace_records(REPLACE): %s\n", win_errstr(werror));
+ if (W_ERROR_EQUAL(werror, WERR_ACCESS_DENIED) &&
+ !needs_add &&
+ orig_rec.dwTtlSeconds == recs[i].dwTtlSeconds)
+ {
+ DBG_NOTICE("dns_replace_records(REPLACE): %s "
+ "=> skip no-op\n",
+ win_errstr(werror));
+ werror = WERR_OK;
+ }
W_ERROR_NOT_OK_RETURN(werror);
return WERR_OK;
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index aba7f41..88aed2e 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -68,6 +68,8 @@ uint8_t werr_to_dns_err(WERROR werr)
return DNS_RCODE_NOTZONE;
} else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
return DNS_RCODE_BADKEY;
+ } else if (W_ERROR_EQUAL(WERR_ACCESS_DENIED, werr)) {
+ return DNS_RCODE_REFUSED;
}
DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
return DNS_RCODE_SERVFAIL;
@@ -642,7 +644,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* The records are sorted with higher types first,
* which puts tombstones (type 0) last.
*/
- return r2->wType - r1->wType;
+ return NUMERIC_CMP(r2->wType, r1->wType);
}
/*
* Then we need to sort from the oldest to newest timestamp.
@@ -650,7 +652,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* Note that dwTimeStamp == 0 (never expiring) records come first,
* then the ones whose expiry is soonest.
*/
- return r1->dwTimeStamp - r2->dwTimeStamp;
+ return NUMERIC_CMP(r1->dwTimeStamp, r2->dwTimeStamp);
}
/*
@@ -1408,7 +1410,7 @@ static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m
/* If the string lengths are not equal just sort by length */
if (l1 != l2) {
/* If m1 is the larger zone name, return it first */
- return l2 - l1;
+ return NUMERIC_CMP(l2, l1);
}
/*TODO: We need to compare DNs here, we want the DomainDNSZones first */