summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Blin <kai@samba.org>2010-09-30 20:35:00 -0700
committerKai Blin <kai@samba.org>2010-10-23 10:17:06 +0000
commita6305c4a168e7d3ac06f824dce05767bc7e9b9c0 (patch)
treec39d6194d08190fd5dd3712fca80a04ca066fa8c
parent69a52290ce81c62f1d6af717c4bd9b6281f0886f (diff)
downloadsamba-a6305c4a168e7d3ac06f824dce05767bc7e9b9c0.tar.gz
samba-a6305c4a168e7d3ac06f824dce05767bc7e9b9c0.tar.bz2
samba-a6305c4a168e7d3ac06f824dce05767bc7e9b9c0.zip
s4 dns: Better error handling when parsing invalid or unknown records
-rw-r--r--librpc/idl/dns.idl4
-rw-r--r--librpc/idl/dnsp.idl4
-rw-r--r--librpc/ndr/ndr_dns.c19
-rw-r--r--source4/dns_server/dns_server.c42
4 files changed, 54 insertions, 15 deletions
diff --git a/librpc/idl/dns.idl b/librpc/idl/dns.idl
index b4075365ab..486b16e50b 100644
--- a/librpc/idl/dns.idl
+++ b/librpc/idl/dns.idl
@@ -60,7 +60,9 @@ interface dns
} dns_rcode;
typedef [public,enum16bit] enum {
- DNS_QCLASS_IP = 0x01
+ DNS_QCLASS_IP = 0x0001,
+ DNS_QCLASS_NONE = 0x00FE,
+ DNS_QCLASS_ANY = 0x00FF
} dns_qclass;
/* These vese values could have been merged with NBT_QTYPE values, but
diff --git a/librpc/idl/dnsp.idl b/librpc/idl/dnsp.idl
index 3a8e384dbe..905e420482 100644
--- a/librpc/idl/dnsp.idl
+++ b/librpc/idl/dnsp.idl
@@ -113,8 +113,8 @@ interface dnsp
dns_record_type wType;
uint32 dwFlags;
uint32 dwSerial;
- uint32 dwTtlSeconds;
- uint32 dwTimeStamp;
+ [flag(NDR_BIG_ENDIAN)] uint32 dwTtlSeconds;
+ uint32 dwTimeStamp;
uint32 dwReserved;
[switch_is(wType)] dnsRecordData data;
} dnsp_DnssrvRpcRecord;
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
index 4f39eb4e67..ee2f1ce5cf 100644
--- a/librpc/ndr/ndr_dns.c
+++ b/librpc/ndr/ndr_dns.c
@@ -220,9 +220,14 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr, int ndr_fl
NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
_saved_offset1 = ndr->offset;
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
- NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, r->rr_type));
- NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
-
+ if (r->length > 0) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, r->rr_type));
+ NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+ if (r->unexpected.length > 0) {
+ return ndr_push_error(ndr, NDR_ERR_LENGTH,
+ "Invalid...Unexpected blob lenght is too large");
+ }
+ }
if (r->unexpected.length > UINT16_MAX) {
return ndr_push_error(ndr, NDR_ERR_LENGTH,
"Unexpected blob lenght is too large");
@@ -260,8 +265,12 @@ _PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr, int ndr_fl
NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
_saved_offset1 = ndr->offset;
- NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, r->rr_type));
- NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+ if (r->length > 0) {
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, r->rr_type));
+ NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+ } else {
+ ZERO_STRUCT(r->rdata);
+ }
length = ndr->offset - _saved_offset1;
if (length > r->length) {
return ndr_pull_error(ndr, NDR_ERR_LENGTH,
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index ac1431cf48..08d6c5dfc2 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -241,6 +241,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_CNAME;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.cname_record = talloc_strdup(ans, recs[ri].data.cname);
ai++;
}
@@ -256,6 +257,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_A;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.ipv4_record = talloc_strdup(ans, recs[ri].data.ipv4);
ai++;
}
@@ -271,6 +273,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_AAAA;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.ipv6_record = recs[ri].data.ipv6;
ai++;
}
@@ -286,6 +289,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_NS;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.ns_record = recs[ri].data.ns;
ai++;
}
@@ -301,6 +305,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_SRV;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.srv_record.priority = recs[ri].data.srv.wPriority;
ans[ai].rdata.srv_record.weight = recs[ri].data.srv.wWeight;
ans[ai].rdata.srv_record.port = recs[ri].data.srv.wPort;
@@ -319,6 +324,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
ans[ai].rr_type = DNS_QTYPE_SOA;
ans[ai].rr_class = DNS_QCLASS_IP;
ans[ai].ttl = recs[ri].dwTtlSeconds;
+ ans[ai].length = UINT16_MAX;
ans[ai].rdata.soa_record.mname = recs[ri].data.soa.mname;
ans[ai].rdata.soa_record.rname = recs[ri].data.soa.rname;
ans[ai].rdata.soa_record.serial = recs[ri].data.soa.serial;
@@ -333,6 +339,10 @@ static NTSTATUS handle_question(struct dns_server *dns,
return NT_STATUS_NOT_IMPLEMENTED;
}
+ if (*ancount == ai) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
*ancount = ai;
*answers = ans;
@@ -401,14 +411,22 @@ static NTSTATUS dns_process(struct dns_server *dns,
{
enum ndr_err_code ndr_err;
NTSTATUS ret;
- struct dns_name_packet *in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
- /* TODO: We don't really need an out_packet. */
- struct dns_name_packet *out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+ struct dns_name_packet *in_packet;
+ struct dns_name_packet *out_packet;
struct dns_res_rec *answers = NULL, *nsrecs = NULL, *additional = NULL;
uint16_t num_answers = 0 , num_nsrecs = 0, num_additional = 0;
uint16_t reply_code;
- if (in_packet == NULL) return NT_STATUS_INVALID_PARAMETER;
+ if (in->length < 12) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+ /* TODO: We don't really need an out_packet. */
+ out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+
+ if (in_packet == NULL) return NT_STATUS_NO_MEMORY;
+ if (out_packet == NULL) return NT_STATUS_NO_MEMORY;
dump_data(2, in->data, in->length);
@@ -417,7 +435,12 @@ static NTSTATUS dns_process(struct dns_server *dns,
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
TALLOC_FREE(in_packet);
DEBUG(0, ("Failed to parse packet %d!\n", ndr_err));
- return NT_STATUS_COULD_NOT_INTERPRET;
+ *out = *in;
+
+ out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
+ out->data[3] |= DNS_RCODE_FORMERR;
+
+ return NT_STATUS_OK;
}
NDR_PRINT_DEBUG(dns_name_packet, in_packet);
@@ -439,7 +462,7 @@ static NTSTATUS dns_process(struct dns_server *dns,
&answers, &num_answers,
&nsrecs, &num_nsrecs,
&additional, &num_additional);
- reply_code = DNS_RCODE_REFUSED;
+ reply_code = DNS_RCODE_NOTIMP;
break;
default:
ret = NT_STATUS_NOT_IMPLEMENTED;
@@ -467,7 +490,12 @@ static NTSTATUS dns_process(struct dns_server *dns,
TALLOC_FREE(in_packet);
TALLOC_FREE(out_packet);
DEBUG(0, ("Failed to push packet %d!\n", ndr_err));
- return NT_STATUS_INTERNAL_ERROR;
+ *out = *in;
+
+ out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
+ out->data[3] |= DNS_RCODE_SERVFAIL;
+
+ return NT_STATUS_OK;
}
dump_data(2, out->data, out->length);