CVE-2016-0771: s4:dns_server: fix idl for dns_txt_record
authorStefan Metzmacher <metze@samba.org>
Fri, 7 Aug 2015 09:36:47 +0000 (11:36 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 10 Mar 2016 05:52:24 +0000 (06:52 +0100)
From RFC 1035:

    3.3.14. TXT RDATA format

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        /                   TXT-DATA                    /
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    where:

    TXT-DATA        One or more <character-string>s.

    TXT RRs are used to hold descriptive text.  The semantics of the text
    depends on the domain where it is found.

Each record contains an array of strings instead of just one string.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11128
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11686

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
librpc/idl/dns.idl
librpc/ndr/ndr_dns.c
librpc/wscript_build
source4/dns_server/dns_query.c
source4/dns_server/dns_update.c

index 1183bd122993fb4d6f0e1fa9ea606552bcc6b710..918073ca9a8aa48d8ada819bdc7980ff998af59c 100644 (file)
@@ -8,7 +8,7 @@
    encoding if it doesn't work out
 */
 
-import "misc.idl";
+import "misc.idl", "dnsp.idl";
 [
        helper("librpc/ndr/ndr_dns.h"),
        helpstring("DNS records"),
@@ -163,9 +163,8 @@ interface dns
                dns_string exchange;
        } dns_mx_record;
 
-       typedef [public] struct {
-               [value(strlen(txt))] uint8 length;
-               [charset(DOS)] uint8 txt[length];
+       typedef [public,nopull] struct {
+               dnsp_string_list txt;
        } dns_txt_record;
 
        typedef [public] struct {
index cc3521791d547917da2fffdb206ecdd4295b43b5..ab0c83a7e84391154e31cc9c9609d85c81688d13 100644 (file)
@@ -30,6 +30,7 @@
 #include "includes.h"
 #include "librpc/gen_ndr/ndr_dns.h"
 #include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
 #include "system/locale.h"
 #include "lib/util/util_net.h"
 
@@ -230,6 +231,29 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
        return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
 }
 
+_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, int ndr_flags, struct dns_txt_record *r)
+{
+       NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+       if (ndr_flags & NDR_SCALARS) {
+               enum ndr_err_code ndr_err;
+               uint32_t data_size = ndr->data_size;
+               uint32_t record_size = 0;
+               ndr_err = ndr_token_retrieve(&ndr->array_size_list, r,
+                                            &record_size);
+               if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       NDR_PULL_NEED_BYTES(ndr, record_size);
+                       ndr->data_size = ndr->offset + record_size;
+               }
+               NDR_CHECK(ndr_pull_align(ndr, 1));
+               NDR_CHECK(ndr_pull_dnsp_string_list(ndr, NDR_SCALARS, &r->txt));
+               NDR_CHECK(ndr_pull_trailer_align(ndr, 1));
+               ndr->data_size = data_size;
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+       }
+       return NDR_ERR_SUCCESS;
+}
+
 _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
                                                int ndr_flags,
                                                const struct dns_res_rec *r)
@@ -302,6 +326,9 @@ _PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
                NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
                _saved_offset1 = ndr->offset;
                if (r->length > 0) {
+                       NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list,
+                                                 &r->rdata,
+                                                 r->length));
                        NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata,
                                                            r->rr_type));
                        NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS,
index 4b849149fa015b0651e3b6a16c40057a54ea357b..20d64f1a9319b528768eda23a2250d611712ac5e 100644 (file)
@@ -32,7 +32,7 @@ bld.SAMBA_SUBSYSTEM('NDR_DNSSERVER',
 
 bld.SAMBA_SUBSYSTEM('NDR_DNS',
     source='gen_ndr/ndr_dns.c ndr/ndr_dns.c',
-    public_deps='ndr'
+    public_deps='ndr NDR_DNSP'
     )
 
 bld.SAMBA_SUBSYSTEM('NDR_DSBACKUP',
index 63c219a3eacea35ce4880064b44d880e350e38aa..c251430a5ef8c65c1633776919b02d90bc54bfd1 100644 (file)
@@ -46,8 +46,7 @@ static WERROR add_response_rr(const char *name,
 {
        struct dns_res_rec *ans = *answers;
        uint16_t ai = talloc_array_length(ans);
-       char *tmp;
-       uint32_t i;
+       enum ndr_err_code ndr_err;
 
        if (ai == UINT16_MAX) {
                return WERR_BUFFER_OVERFLOW;
@@ -114,14 +113,12 @@ static WERROR add_response_rr(const char *name,
                }
                break;
        case DNS_QTYPE_TXT:
-               tmp = talloc_asprintf(ans, "\"%s\"", rec->data.txt.str[0]);
-               W_ERROR_HAVE_NO_MEMORY(tmp);
-               for (i=1; i<rec->data.txt.count; i++) {
-                       tmp = talloc_asprintf_append_buffer(
-                               tmp, " \"%s\"", rec->data.txt.str[i]);
-                       W_ERROR_HAVE_NO_MEMORY(tmp);
+               ndr_err = ndr_dnsp_string_list_copy(ans,
+                                                   &rec->data.txt,
+                                                   &ans[ai].rdata.txt_record.txt);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_NOMEM;
                }
-               ans[ai].rdata.txt_record.txt = tmp;
                break;
        default:
                DEBUG(0, ("Got unhandled type %u query.\n", rec->wType));
@@ -145,6 +142,7 @@ static WERROR add_dns_res_rec(struct dns_res_rec **pdst,
 {
        struct dns_res_rec *dst = *pdst;
        uint16_t di = talloc_array_length(dst);
+       enum ndr_err_code ndr_err;
 
        if (di == UINT16_MAX) {
                return WERR_BUFFER_OVERFLOW;
@@ -248,9 +246,10 @@ static WERROR add_dns_res_rec(struct dns_res_rec **pdst,
                }
                break;
        case DNS_QTYPE_TXT:
-               dst[di].rdata.txt_record.txt = talloc_strdup(
-                       dst, src->rdata.txt_record.txt);
-               if (dst[di].rdata.txt_record.txt == NULL) {
+               ndr_err = ndr_dnsp_string_list_copy(dst,
+                                                   &src->rdata.txt_record.txt,
+                                                   &dst[di].rdata.txt_record.txt);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        return WERR_NOMEM;
                }
                break;
index c002b4d8fffd9f87248bf3d8eed59da5fb482347..60a4b366a01514831a72e47e81035090c7cfcdd7 100644 (file)
@@ -299,9 +299,7 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                             const struct dns_res_rec *rrec,
                             struct dnsp_DnssrvRpcRecord *r)
 {
-       char *tmp;
-       char *txt_record_txt;
-       char *saveptr = NULL;
+       enum ndr_err_code ndr_err;
 
        if (rrec->rr_type == DNS_QTYPE_ALL) {
                return DNS_ERR(FORMAT_ERROR);
@@ -354,28 +352,11 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                W_ERROR_HAVE_NO_MEMORY(r->data.mx.nameTarget);
                break;
        case DNS_QTYPE_TXT:
-               r->data.txt.count = 0;
-               r->data.txt.str = talloc_array(mem_ctx, const char *,
-                                              r->data.txt.count);
-               W_ERROR_HAVE_NO_MEMORY(r->data.txt.str);
-
-               txt_record_txt = talloc_strdup(r->data.txt.str,
-                                              rrec->rdata.txt_record.txt);
-               W_ERROR_HAVE_NO_MEMORY(txt_record_txt);
-
-               tmp = strtok_r(txt_record_txt, "\"", &saveptr);
-               while (tmp) {
-                       if (strcmp(tmp, " ") == 0) {
-                               tmp = strtok_r(NULL, "\"", &saveptr);
-                               continue;
-                       }
-                       r->data.txt.str = talloc_realloc(mem_ctx, r->data.txt.str, const char *,
-                                                       r->data.txt.count+1);
-                       r->data.txt.str[r->data.txt.count] = talloc_strdup(r->data.txt.str, tmp);
-                       W_ERROR_HAVE_NO_MEMORY(r->data.txt.str[r->data.txt.count]);
-
-                       r->data.txt.count++;
-                       tmp = strtok_r(NULL, "\"", &saveptr);
+               ndr_err = ndr_dnsp_string_list_copy(mem_ctx,
+                                                   &rrec->rdata.txt_record.txt,
+                                                   &r->data.txt);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_NOMEM;
                }
 
                break;