[SCM] Samba Shared Repository - branch v4-4-test updated

Karolin Seeger kseeger at samba.org
Thu Jun 23 13:54:02 UTC 2016


The branch, v4-4-test has been updated
       via  ac41e16 selftest: Add a DNS test matching Windows
       via  6ec1a8a s4: dns: Correctly check for talloc failure.
       via  6aeed14 selftest: add test for DNS updates with TKEY/TSIG
       via  3f7f433 s4/dns_server: enable sending of TSIG error records
       via  ea2d415 s4/dns_server: prepare sending correct error responses for dns_verify_tsig() errors
       via  1c8d127 s4/dns_server: don't compute TSIG MAC in TSIG error records
       via  721a858 s4/dns_server: error codes for failing MAC verification in TSIG requests
       via  f116a7b s4/dns_server: ensure we store the key name in error code paths
       via  0822257 s4/dns_server: not finding the key here is a fatal error
       via  001d7dd s4/dns_server: split out function that does the MAC computation
       via  c56d05c s4/dns_server: include request MAC in TSIG response MAC calculation
       via  d2ab8d3 librpc/dns: remove original_id from dns_fake_tsig_rec
       via  33a6532 librpc/dns: don't compress strings in TKEY and TSIG responses
       via  d4cf68c librpc/ndr: add flag LIBNDR_FLAG_NO_COMPRESSION
      from  ddcf7b7 libnet: ignore realm setting for domain security joins to AD domains if 'winbind rpc only = true'

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-4-test


- Log -----------------------------------------------------------------
commit ac41e16d40e98dff76283e22b5f8fd13fdb6466d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jun 10 15:40:59 2016 +1200

    selftest: Add a DNS test matching Windows
    
    This performs the same steps as Windows does
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit c752e93fc5960d2d31d80fcf608eff0fbfa784a0)
    
    Autobuild-User(v4-4-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-4-test): Thu Jun 23 15:53:05 CEST 2016 on sn-devel-144

commit 6ec1a8a99f86558a8d4b89357618503caab0a40e
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Jun 15 21:25:59 2016 -0700

    s4: dns: Correctly check for talloc failure.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Volker Lendecke <vl at samba.org>
    
    Autobuild-User(master): Volker Lendecke <vl at samba.org>
    Autobuild-Date(master): Thu Jun 16 16:55:15 CEST 2016 on sn-devel-144
    
    (cherry picked from commit c3dfeb3aa6c7df5127022abc090e446adc1b7d71)

commit 6aeed14be480979d6aabd67c6eac56dc01c2c6cf
Author: Ralph Boehme <slow at samba.org>
Date:   Wed May 4 14:26:16 2016 +0200

    selftest: add test for DNS updates with TKEY/TSIG
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    
    Autobuild-User(master): Garming Sam <garming at samba.org>
    Autobuild-Date(master): Thu Jun 16 04:07:41 CEST 2016 on sn-devel-144
    
    (backported from commit 721b21bb801735fe9179502ff34e7a707176dbd8)

commit 3f7f4333682e5b347be0accf211eb99af139d5f0
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:44:00 2016 +0200

    s4/dns_server: enable sending of TSIG error records
    
    This final patch enables sending TSIG error records by adding
    DNS_RCODE_NOTAUTH to the set of error conditions that are allowed to
    trigger sending a full generated response.
    
    See RFC 2845 "4.5.1. KEY check and error handling" and "4.5.3. MAC check
    and error handling".
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 88700e7d890c017e2d360fe4385e196f4016db4a)

commit ea2d4158184b62b0995afe47f36dc9330a231fe2
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:42:14 2016 +0200

    s4/dns_server: prepare sending correct error responses for dns_verify_tsig() errors
    
    Call dns_verify_tsig() after updating state.flags and assign and use
    out_packet for dns_verify_tsig().
    
    We will need the updated flags when sending TSIG error responses when
    TSIG request MAC verification fails and dns_verify_tsig() uses the
    passed in packet as response, so we have to make sure we copy in_packet
    to out_packet before calling out and pass out_packet.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit ba683d459e1b1550d0a4de3a0f576c857ee595c8)

commit 1c8d1279334981b6cf78420d760cdceca46c599b
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 17:25:56 2016 +0200

    s4/dns_server: don't compute TSIG MAC in TSIG error records
    
    See RFC 2845 "4.3. TSIG on TSIG Error returns".
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 8f46bf2102a91c5f2d5beee530ece0387fdfbb0c)

commit 721a858376adfbb125b9f168727fd5db4d8e5621
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:40:45 2016 +0200

    s4/dns_server: error codes for failing MAC verification in TSIG requests
    
    According to RFC 2845 "4.5.3. MAC check and error handling" we must
    return NOTAUTH and DNS_RCODE_BADSIG when MAC verification fails.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 8b4a2dcf38e9f38bb99bd1daa5e0d5da176a1e15)

commit f116a7bdeb24f69d96da0dd49b5079184f9ff5c3
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:37:32 2016 +0200

    s4/dns_server: ensure we store the key name in error code paths
    
    We need the TKEY name when adding TSIG records to error responses.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 77c5bfdce417a36b523e9901668fbff0d42f1ed2)

commit 0822257f2e00d49108c3cf4b864aa703cee49788
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:56:21 2016 +0200

    s4/dns_server: not finding the key here is a fatal error
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit c1fca8fa398461fb0a67dbb0e181c71b83a32b62)

commit 001d7dd43ea3eee6962f17701db4a70e87f33f63
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 30 16:03:33 2016 +0200

    s4/dns_server: split out function that does the MAC computation
    
    Split out function that does the MAC computation from the TSIG record
    creating function. This will later simplify the code when creating error
    responsed to TSIG requests with bad MACs where we have to add the TSIG
    record with an empty MAC.
    
    No functional behaviour change besides hard coding "gss-tsig" algorithm
    name: later when sending a TSIG error response for a TKEY request with a
    bad keyname, we won't have a tkey to fetch the algorithm name from.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 830316ce84c6f4994841a1c68e60d90225a2963d)

commit c56d05cb48432a80498cedc6843d3888e9a59c07
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 23 19:09:05 2016 +0200

    s4/dns_server: include request MAC in TSIG response MAC calculation
    
    According to RFC 2845 "4.2 TSIG on Answers", when the request is signed,
    the request MAC must be included in the response MAC calculation.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit 8ed125e8bb13904638f8506e860c169f788e8ee9)

commit d2ab8d34e2d76885ed89d7930c96092e65624b66
Author: Ralph Boehme <slow at samba.org>
Date:   Sat May 14 19:08:51 2016 +0200

    librpc/dns: remove original_id from dns_fake_tsig_rec
    
    Cf RFC2845, 3.4.2. "TSIG Variables", the request id (original_id) is not
    used in the MAC calculation. This also explains the mysterious 2 bytes
    padding.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit bea4aec521576576b8dc55065f11c6c5025d9c4f)

commit 33a6532252382fba78e5d423f0ef7c0d9ad1a4d0
Author: Ralph Boehme <slow at samba.org>
Date:   Tue May 17 14:34:52 2016 +0200

    librpc/dns: don't compress strings in TKEY and TSIG responses
    
    Certain DNS clients fail TSIG record MAC validation if the TSIG record
    contains compressed strings.
    
    Windows DNS server behaviour seems to be to not send compressed names in
    TKEY and TSIG records.
    
    This patch ensures we conform to this behaviour.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit a51f9989564c28aeece50b56a59e9bb60d41340b)

commit d4cf68c5ae780fad51696d12dfd9d7546cc42f03
Author: Ralph Boehme <slow at samba.org>
Date:   Tue May 17 12:30:46 2016 +0200

    librpc/ndr: add flag LIBNDR_FLAG_NO_COMPRESSION
    
    This flag can be used to change marshalling behaviour with regard to
    compression.
    
    Example: DNS packets make use of so called DNS name compression which
    means that for identical strings in a DNS packet, the second string is
    replaced with a reference (an offset) to the first.
    
    Setting this flag requests to turns off the marshalling compression.
    
    This will be used in the next commit to prevent name compression in DNS
    TSIG records.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    (cherry picked from commit df079962ef708de96e54ded13da04b6e12ac00d0)

-----------------------------------------------------------------------

Summary of changes:
 librpc/idl/dns.idl              |   7 +-
 librpc/idl/idl_types.h          |   1 +
 librpc/ndr/libndr.h             |   3 +
 librpc/ndr/ndr_dns.c            |  63 +++--
 python/samba/tests/dns_tkey.py  | 563 ++++++++++++++++++++++++++++++++++++++++
 source4/dns_server/dns_crypto.c | 150 ++++++++---
 source4/dns_server/dns_server.c |  19 +-
 source4/selftest/tests.py       |   2 +
 8 files changed, 731 insertions(+), 77 deletions(-)
 create mode 100644 python/samba/tests/dns_tkey.py


Changeset truncated at 500 lines:

diff --git a/librpc/idl/dns.idl b/librpc/idl/dns.idl
index 5435fcf..aebb106 100644
--- a/librpc/idl/dns.idl
+++ b/librpc/idl/dns.idl
@@ -179,7 +179,7 @@ interface dns
 		uint8      option_data[option_length];
 	} dns_opt_record;
 
-	typedef [public] struct {
+	typedef [flag(NDR_NO_COMP),public] struct {
 		dns_string     algorithm;
 		uint32         inception;
 		uint32         expiration;
@@ -191,7 +191,7 @@ interface dns
 		uint8          other_data[other_size];
 	} dns_tkey_record;
 
-	typedef [public] struct {
+	typedef [flag(NDR_NO_COMP),public] struct {
 		dns_string algorithm_name;
 		uint16     time_prefix; /* 0 until February 2106*/
 		uint32     time;
@@ -204,7 +204,7 @@ interface dns
 		uint8      other_data[other_size];
 	} dns_tsig_record;
 
-	typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+	typedef [flag(NDR_NO_COMP|NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
 		dns_string	name;
 		dns_qclass 	rr_class;
 		uint32     	ttl;
@@ -212,7 +212,6 @@ interface dns
 		uint16     	time_prefix; /* 0 until February 2106*/
 		uint32     	time;
 		uint16     	fudge;
-		uint16     	original_id;
 		uint16     	error;
 		uint16     	other_size;
 		uint8      	other_data[other_size];
diff --git a/librpc/idl/idl_types.h b/librpc/idl/idl_types.h
index 838c219..72a5d85 100644
--- a/librpc/idl/idl_types.h
+++ b/librpc/idl/idl_types.h
@@ -40,6 +40,7 @@
 #define NDR_ALIGN2        LIBNDR_FLAG_ALIGN2
 #define NDR_ALIGN4        LIBNDR_FLAG_ALIGN4
 #define NDR_ALIGN8        LIBNDR_FLAG_ALIGN8
+#define NDR_NO_COMP       LIBNDR_FLAG_NO_COMPRESSION
 
 /* this flag is used to force a section of IDL as little endian. It is
    needed for the epmapper IDL, which is defined as always being LE */
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
index c6116ed..2275f16 100644
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -125,6 +125,9 @@ struct ndr_print {
 #define LIBNDR_FLAG_STR_RAW8		(1<<13)
 #define LIBNDR_STRING_FLAGS		(0x7FFC)
 
+/* Disable string token compression  */
+#define LIBNDR_FLAG_NO_COMPRESSION	(1<<15)
+
 /*
  * don't debug NDR_ERR_BUFSIZE failures,
  * as the available buffer might be incomplete.
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
index ab0c83a..7e6286a 100644
--- a/librpc/ndr/ndr_dns.c
+++ b/librpc/ndr/ndr_dns.c
@@ -169,28 +169,30 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
 		size_t complen;
 		uint32_t offset;
 
-		/* see if we have pushed the remaining string already,
-		 * if so we use a label pointer to this string
-		 */
-		ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s,
-						    &offset,
-						    (comparison_fn_t)strcmp,
-						    false);
-		if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-			uint8_t b[2];
-
-			if (offset > 0x3FFF) {
-				return ndr_push_error(ndr, NDR_ERR_STRING,
-						      "offset for dns string " \
-						      "label pointer " \
-						      "%u[%08X] > 0x00003FFF",
-						      offset, offset);
+		if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
+			/* see if we have pushed the remaining string already,
+			 * if so we use a label pointer to this string
+			 */
+			ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s,
+							    &offset,
+							    (comparison_fn_t)strcmp,
+							    false);
+			if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+				uint8_t b[2];
+
+				if (offset > 0x3FFF) {
+					return ndr_push_error(ndr, NDR_ERR_STRING,
+							      "offset for dns string " \
+							      "label pointer " \
+							      "%u[%08X] > 0x00003FFF",
+							      offset, offset);
+				}
+
+				b[0] = 0xC0 | (offset>>8);
+				b[1] = (offset & 0xFF);
+
+				return ndr_push_bytes(ndr, b, 2);
 			}
-
-			b[0] = 0xC0 | (offset>>8);
-			b[1] = (offset & 0xFF);
-
-			return ndr_push_bytes(ndr, b, 2);
 		}
 
 		complen = strcspn(s, ".");
@@ -213,8 +215,10 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
 		/* remember the current componemt + the rest of the string
 		 * so it can be reused later
 		 */
-		NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s,
-					  ndr->offset));
+		if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
+			NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s,
+						  ndr->offset));
+		}
 
 		/* push just this component into the blob */
 		NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
@@ -264,8 +268,21 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
 	ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
 				   LIBNDR_FLAG_NOALIGN);
 	if (ndr_flags & NDR_SCALARS) {
+		uint32_t _flags_save_name = ndr->flags;
+
 		NDR_CHECK(ndr_push_align(ndr, 4));
+
+		switch (r->rr_type) {
+		case DNS_QTYPE_TKEY:
+		case DNS_QTYPE_TSIG:
+			ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_COMPRESSION);
+			break;
+		default:
+			break;
+		}
 		NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name));
+		ndr->flags = _flags_save_name;
+
 		NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type));
 		NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class));
 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py
new file mode 100644
index 0000000..f424e07
--- /dev/null
+++ b/python/samba/tests/dns_tkey.py
@@ -0,0 +1,563 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kai Blin  <kai at samba.org> 2011
+# Copyright (C) Ralph Boehme  <slow at samba.org> 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import struct
+import random
+import socket
+import optparse
+import uuid
+import time
+import samba.ndr as ndr
+import samba.getopt as options
+from samba import credentials
+from samba.dcerpc import dns, dnsp
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+from samba import gensec, tests
+
+parser = optparse.OptionParser("dns.py <server name> <server ip> [options]")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+
+# This timeout only has relevance when testing against Windows
+# Format errors tend to return patchy responses, so a timeout is needed.
+parser.add_option("--timeout", type="int", dest="timeout",
+                  help="Specify timeout for DNS requests")
+
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+subunitopts = SubunitOptions(parser)
+parser.add_option_group(subunitopts)
+
+opts, args = parser.parse_args()
+timeout = opts.timeout
+
+if len(args) < 2:
+    parser.print_usage()
+    sys.exit(1)
+
+server_name = args[0]
+server_ip = args[1]
+
+
+class DNSTest(tests.TestCase):
+    def setUp(self):
+        super(DNSTest, self).setUp()
+        self.server = server_name
+        self.server_ip = server_ip
+        self.settings = {}
+        self.settings["lp_ctx"] = self.lp_ctx = tests.env_loadparm()
+        self.settings["target_hostname"] = self.server
+
+        self.creds = credentials.Credentials()
+        self.creds.guess(self.lp_ctx)
+        self.creds.set_username(tests.env_get_var_value('USERNAME'))
+        self.creds.set_password(tests.env_get_var_value('PASSWORD'))
+        self.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
+        self.newrecname = "tkeytsig.%s" % self.get_dns_domain()
+
+    def errstr(self, errcode):
+        "Return a readable error code"
+        string_codes = [
+            "OK",
+            "FORMERR",
+            "SERVFAIL",
+            "NXDOMAIN",
+            "NOTIMP",
+            "REFUSED",
+            "YXDOMAIN",
+            "YXRRSET",
+            "NXRRSET",
+            "NOTAUTH",
+            "NOTZONE",
+            "0x0B",
+            "0x0C",
+            "0x0D",
+            "0x0E",
+            "0x0F",
+            "BADSIG",
+            "BADKEY"
+        ]
+
+        return string_codes[errcode]
+
+    def assert_rcode_equals(self, rcode, expected):
+        "Helper function to check return code"
+        self.assertEquals(rcode, expected, "Expected RCODE %s, got %s" %
+                          (self.errstr(expected), self.errstr(rcode)))
+
+    def assert_dns_rcode_equals(self, packet, rcode):
+        "Helper function to check return code"
+        p_errcode = packet.operation & 0x000F
+        self.assertEquals(p_errcode, rcode, "Expected RCODE %s, got %s" %
+                          (self.errstr(rcode), self.errstr(p_errcode)))
+
+    def assert_dns_opcode_equals(self, packet, opcode):
+        "Helper function to check opcode"
+        p_opcode = packet.operation & 0x7800
+        self.assertEquals(p_opcode, opcode, "Expected OPCODE %s, got %s" %
+                          (opcode, p_opcode))
+
+    def make_name_packet(self, opcode, qid=None):
+        "Helper creating a dns.name_packet"
+        p = dns.name_packet()
+        if qid is None:
+            p.id = random.randint(0x0, 0xff00)
+        p.operation = opcode
+        p.questions = []
+        p.additional = []
+        return p
+
+    def finish_name_packet(self, packet, questions):
+        "Helper to finalize a dns.name_packet"
+        packet.qdcount = len(questions)
+        packet.questions = questions
+
+    def make_name_question(self, name, qtype, qclass):
+        "Helper creating a dns.name_question"
+        q = dns.name_question()
+        q.name = name
+        q.question_type = qtype
+        q.question_class = qclass
+        return q
+
+    def make_txt_record(self, records):
+        rdata_txt = dns.txt_record()
+        s_list = dnsp.string_list()
+        s_list.count = len(records)
+        s_list.str = records
+        rdata_txt.txt = s_list
+        return rdata_txt
+
+    def get_dns_domain(self):
+        "Helper to get dns domain"
+        return self.creds.get_realm().lower()
+
+    def dns_transaction_udp(self, packet, host,
+                            dump=False, timeout=timeout):
+        "send a DNS query and read the reply"
+        s = None
+        try:
+            send_packet = ndr.ndr_pack(packet)
+            if dump:
+                print self.hexdump(send_packet)
+            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
+            s.settimeout(timeout)
+            s.connect((host, 53))
+            s.sendall(send_packet, 0)
+            recv_packet = s.recv(2048, 0)
+            if dump:
+                print self.hexdump(recv_packet)
+            response = ndr.ndr_unpack(dns.name_packet, recv_packet)
+            return (response, recv_packet)
+        finally:
+            if s is not None:
+                s.close()
+
+    def dns_transaction_tcp(self, packet, host,
+                            dump=False, timeout=timeout):
+        "send a DNS query and read the reply, also return the raw packet"
+        s = None
+        try:
+            send_packet = ndr.ndr_pack(packet)
+            if dump:
+                print self.hexdump(send_packet)
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+            s.settimeout(timeout)
+            s.connect((host, 53))
+            tcp_packet = struct.pack('!H', len(send_packet))
+            tcp_packet += send_packet
+            s.sendall(tcp_packet)
+
+            recv_packet = s.recv(0xffff + 2, 0)
+            if dump:
+                print self.hexdump(recv_packet)
+            response = ndr.ndr_unpack(dns.name_packet, recv_packet[2:])
+
+        finally:
+            if s is not None:
+                s.close()
+
+        # unpacking and packing again should produce same bytestream
+        my_packet = ndr.ndr_pack(response)
+        self.assertEquals(my_packet, recv_packet[2:])
+
+        return (response, recv_packet[2:])
+
+    def tkey_trans(self):
+        "Do a TKEY transaction and establish a gensec context"
+
+        self.key_name = "%s.%s" % (uuid.uuid4(), self.get_dns_domain())
+
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        q = self.make_name_question(self.key_name,
+                                    dns.DNS_QTYPE_TKEY,
+                                    dns.DNS_QCLASS_IN)
+        questions = []
+        questions.append(q)
+        self.finish_name_packet(p, questions)
+
+        r = dns.res_rec()
+        r.name = self.key_name
+        r.rr_type = dns.DNS_QTYPE_TKEY
+        r.rr_class = dns.DNS_QCLASS_IN
+        r.ttl = 0
+        r.length = 0xffff
+        rdata = dns.tkey_record()
+        rdata.algorithm = "gss-tsig"
+        rdata.inception = int(time.time())
+        rdata.expiration = int(time.time()) + 60*60
+        rdata.mode = dns.DNS_TKEY_MODE_GSSAPI
+        rdata.error = 0
+        rdata.other_size = 0
+
+        self.g = gensec.Security.start_client(self.settings)
+        self.g.set_credentials(self.creds)
+        self.g.set_target_service("dns")
+        self.g.set_target_hostname(self.server)
+        self.g.want_feature(gensec.FEATURE_SIGN)
+        self.g.start_mech_by_name("spnego")
+
+        finished = False
+        client_to_server = ""
+
+        (finished, server_to_client) = self.g.update(client_to_server)
+        self.assertFalse(finished)
+
+        data = [ord(x) for x in list(server_to_client)]
+        rdata.key_data = data
+        rdata.key_size = len(data)
+        r.rdata = rdata
+
+        additional = [r]
+        p.arcount = 1
+        p.additional = additional
+
+        (response, response_packet) = self.dns_transaction_tcp(p, self.server_ip)
+        self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+
+        tkey_record = response.answers[0].rdata
+        data = [chr(x) for x in tkey_record.key_data]
+        server_to_client = ''.join(data)
+        (finished, client_to_server) = self.g.update(server_to_client)
+        self.assertTrue(finished)
+
+        self.verify_packet(response, response_packet)
+
+    def verify_packet(self, response, response_packet, request_mac=""):
+        self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG)
+
+        tsig_record = response.additional[0].rdata
+        mac = ''.join([chr(x) for x in tsig_record.mac])
+
+        # Cut off tsig record from dns response packet for MAC verification
+        # and reset additional record count.
+        key_name_len = len(self.key_name) + 2
+        tsig_record_len = len(ndr.ndr_pack(tsig_record)) + key_name_len + 10
+
+        response_packet_list = list(response_packet)
+        del response_packet_list[-tsig_record_len:]
+        response_packet_list[11] = chr(0)
+        response_packet_wo_tsig = ''.join(response_packet_list)
+
+        fake_tsig = dns.fake_tsig_rec()
+        fake_tsig.name = self.key_name
+        fake_tsig.rr_class = dns.DNS_QCLASS_ANY
+        fake_tsig.ttl = 0
+        fake_tsig.time_prefix = tsig_record.time_prefix
+        fake_tsig.time = tsig_record.time
+        fake_tsig.algorithm_name = tsig_record.algorithm_name
+        fake_tsig.fudge = tsig_record.fudge
+        fake_tsig.error = 0
+        fake_tsig.other_size = 0
+        fake_tsig_packet = ndr.ndr_pack(fake_tsig)
+
+        data = request_mac + response_packet_wo_tsig + fake_tsig_packet
+        self.g.check_packet(data, data, mac)
+
+    def sign_packet(self, packet, key_name):
+        "Sign a packet, calculate a MAC and add TSIG record"
+        packet_data = ndr.ndr_pack(packet)
+
+        fake_tsig = dns.fake_tsig_rec()
+        fake_tsig.name = key_name
+        fake_tsig.rr_class = dns.DNS_QCLASS_ANY
+        fake_tsig.ttl = 0
+        fake_tsig.time_prefix = 0
+        fake_tsig.time = int(time.time())
+        fake_tsig.algorithm_name = "gss-tsig"
+        fake_tsig.fudge = 300
+        fake_tsig.error = 0
+        fake_tsig.other_size = 0
+        fake_tsig_packet = ndr.ndr_pack(fake_tsig)
+
+        data = packet_data + fake_tsig_packet
+        mac = self.g.sign_packet(data, data)
+        mac_list = [ord(x) for x in list(mac)]
+
+        rdata = dns.tsig_record()
+        rdata.algorithm_name = "gss-tsig"
+        rdata.time_prefix = 0
+        rdata.time = fake_tsig.time
+        rdata.fudge = 300
+        rdata.original_id = packet.id
+        rdata.error = 0
+        rdata.other_size = 0
+        rdata.mac = mac_list
+        rdata.mac_size = len(mac_list)
+
+        r = dns.res_rec()
+        r.name = key_name
+        r.rr_type = dns.DNS_QTYPE_TSIG
+        r.rr_class = dns.DNS_QCLASS_ANY
+        r.ttl = 0
+        r.length = 0xffff
+        r.rdata = rdata
+
+        additional = [r]
+        packet.additional = additional
+        packet.arcount = 1
+
+        return mac
+


-- 
Samba Shared Repository



More information about the samba-cvs mailing list