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)
committerKarolin Seeger <kseeger@samba.org>
Wed, 24 Feb 2016 10:43:58 +0000 (11:43 +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 0b9e3b05071c35a26c26e940ab547e0ceeff85b3..065d992684ce11b151d69e2fde208048f6a83392 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 a8a900479098aca2207a45c3830608b5b1a5f950..30820d2c034ad5079760ecef480a827ac4b5d63f 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 77f797bf5b256689039284a8cff2561fd354556d..f246958a94bf15bd22ead9c89a273ec5cfc39eb4 100644 (file)
@@ -46,8 +46,7 @@ static WERROR create_response_rr(const struct dns_name_question *question,
 {
        struct dns_res_rec *ans = *answers;
        uint16_t ai = *ancount;
-       char *tmp;
-       uint32_t i;
+       enum ndr_err_code ndr_err;
 
        ZERO_STRUCT(ans[ai]);
 
@@ -101,14 +100,12 @@ static WERROR create_response_rr(const struct dns_name_question *question,
                }
                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));
index 04e7d9adff7a44e31bf8eb1e21283708eba7e046..fb02ba074d4e66d5d94abaff15350a70319dec62 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;