diff options
author | Kai Blin <kai@samba.org> | 2010-09-30 20:35:00 -0700 |
---|---|---|
committer | Kai Blin <kai@samba.org> | 2010-10-23 10:17:06 +0000 |
commit | a6305c4a168e7d3ac06f824dce05767bc7e9b9c0 (patch) | |
tree | c39d6194d08190fd5dd3712fca80a04ca066fa8c | |
parent | 69a52290ce81c62f1d6af717c4bd9b6281f0886f (diff) | |
download | samba-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.idl | 4 | ||||
-rw-r--r-- | librpc/idl/dnsp.idl | 4 | ||||
-rw-r--r-- | librpc/ndr/ndr_dns.c | 19 | ||||
-rw-r--r-- | source4/dns_server/dns_server.c | 42 |
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); |