From e4e9b525fead6f6f62aa35df7619b6cb3b1cdf95 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:11:24 +0200 Subject: [PATCH 01/28] python:tests/dns_base: generate a real signature in bad_sign_packet() We just destroy the signature bytes but keep the header unchanged. This makes it easier to look at it in wireshark. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit ae23d512a724650ae2de1178ac43deff8266aa56) --- python/samba/tests/dns_base.py | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index b92371e9cdd5..a4f476dd2e41 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -317,7 +317,7 @@ class DNSTKeyTest(DNSTest): data = request_mac + response_packet_wo_tsig + fake_tsig_packet self.g.check_packet(data, data, mac) - def sign_packet(self, packet, key_name): + def sign_packet(self, packet, key_name, bad_sig=False): "Sign a packet, calculate a MAC and add TSIG record" packet_data = ndr.ndr_pack(packet) @@ -336,6 +336,23 @@ class DNSTKeyTest(DNSTest): data = packet_data + fake_tsig_packet mac = self.g.sign_packet(data, data) mac_list = [x if isinstance(x, int) else ord(x) for x in list(mac)] + if bad_sig: + if len(mac) > 8: + mac_list[-8] = mac_list[-8] ^ 0xff + if len(mac) > 7: + mac_list[-7] = ord('b') + if len(mac) > 6: + mac_list[-6] = ord('a') + if len(mac) > 5: + mac_list[-5] = ord('d') + if len(mac) > 4: + mac_list[-4] = ord('m') + if len(mac) > 3: + mac_list[-3] = ord('a') + if len(mac) > 2: + mac_list[-2] = ord('c') + if len(mac) > 1: + mac_list[-1] = mac_list[-1] ^ 0xff rdata = dns.tsig_record() rdata.algorithm_name = "gss-tsig" @@ -363,33 +380,10 @@ class DNSTKeyTest(DNSTest): return mac def bad_sign_packet(self, packet, key_name): - '''Add bad signature for a packet by bitflipping - the final byte in the MAC''' + """Add bad signature for a packet by + bitflipping and hardcoding bytes at the end of the MAC""" - mac_list = [x if isinstance(x, int) else ord(x) for x in list("badmac")] - - rdata = dns.tsig_record() - rdata.algorithm_name = "gss-tsig" - rdata.time_prefix = 0 - rdata.time = int(time.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 self.sign_packet(packet, key_name, bad_sig=True) def search_record(self, name): p = self.make_name_packet(dns.DNS_OPCODE_QUERY) -- 2.34.1 From f86498e5e050ffb47179b4a10e0c428ae05fc3e3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:16:40 +0200 Subject: [PATCH 02/28] python:tests/dns_base: use ndr_deepcopy() and ndr_pack() in verify_packet() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit c594cbad4af97031bb7b5b0eb2fb228b00acf646) --- python/samba/tests/dns_base.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index a4f476dd2e41..b23a421db0a1 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -283,24 +283,20 @@ class DNSTKeyTest(DNSTest): self.verify_packet(response, response_packet) def verify_packet(self, response, response_packet, request_mac=b""): + self.assertEqual(response.arcount, 1) self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG) tsig_record = response.additional[0].rdata mac = bytes(tsig_record.mac) + self.assertEqual(tsig_record.original_id, response.id) + self.assertEqual(tsig_record.mac_size, len(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 - - # convert str/bytes to a list (of string char or int) - # so it can be modified - response_packet_list = [x if isinstance(x, int) else ord(x) for x in response_packet] - del response_packet_list[-tsig_record_len:] - response_packet_list[11] = 0 - - # convert modified list (of string char or int) to str/bytes - response_packet_wo_tsig = bytes(response_packet_list) + response_copy = ndr.ndr_deepcopy(response) + response_copy.arcount = 0 + response_packet_wo_tsig = ndr.ndr_pack(response_copy) fake_tsig = dns.fake_tsig_rec() fake_tsig.name = self.key_name @@ -310,8 +306,9 @@ class DNSTKeyTest(DNSTest): 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.error = tsig_record.error + fake_tsig.other_size = tsig_record.other_size + fake_tsig.other_data = tsig_record.other_data fake_tsig_packet = ndr.ndr_pack(fake_tsig) data = request_mac + response_packet_wo_tsig + fake_tsig_packet -- 2.34.1 From 8187d94f72a94425f6d03f9f964ccfcf656180c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:07:24 +0200 Subject: [PATCH 03/28] python:tests/dns_base: let dns_transaction_tcp() handle short receives With socket_wrapper we only get 1500 byte chunks... BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit c741d0f3969abe821e8ee2a10f848159eb2749fe) --- python/samba/tests/dns_base.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index b23a421db0a1..3c9d50733833 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -151,7 +151,18 @@ class DNSTest(TestCaseInTempDir): tcp_packet += send_packet s.sendall(tcp_packet) - recv_packet = s.recv(0xffff + 2, 0) + recv_packet = b'' + length = None + for i in range(0, 2 + 0xffff): + if len(recv_packet) >= 2: + length, = struct.unpack('!H', recv_packet[0:2]) + remaining = 2 + length + else: + remaining = 2 + 12 + remaining -= len(recv_packet) + if remaining == 0: + break + recv_packet += s.recv(remaining, 0) if dump: print(self.hexdump(recv_packet)) response = ndr.ndr_unpack(dns.name_packet, recv_packet[2:]) -- 2.34.1 From 687e8f564bcaded0961596d7a17cc06b284a9301 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:35:58 +0200 Subject: [PATCH 04/28] python:tests/dns_base: add self.assert_echoed_dns_error() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit ce591464cb12ab00a5d5752a7cea5f909c3c3f1b) --- python/samba/tests/dns_base.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 3c9d50733833..909a9743691f 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -76,6 +76,24 @@ class DNSTest(TestCaseInTempDir): self.assertEqual(p_opcode, opcode, "Expected OPCODE %s, got %s" % (opcode, p_opcode)) + def assert_dns_flags_equals(self, packet, flags): + "Helper function to check opcode" + p_flags = packet.operation & (~(dns.DNS_OPCODE|dns.DNS_RCODE)) + self.assertEqual(p_flags, flags, "Expected FLAGS %02x, got %02x" % + (flags, p_flags)) + + def assert_echoed_dns_error(self, request, response, response_p, rcode): + + request_p = ndr.ndr_pack(request) + + self.assertEqual(response.id, request.id) + self.assert_dns_rcode_equals(response, rcode) + self.assert_dns_opcode_equals(response, request.operation & dns.DNS_OPCODE) + self.assert_dns_flags_equals(response, + (request.operation | dns.DNS_FLAG_REPLY) & (~(dns.DNS_OPCODE|dns.DNS_RCODE))) + self.assertEqual(len(response_p), len(request_p)) + self.assertEqual(response_p[4:], request_p[4:]) + def make_name_packet(self, opcode, qid=None): "Helper creating a dns.name_packet" p = dns.name_packet() -- 2.34.1 From 39d46a2bee0fc696701cd8e25082477237626b17 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:35:58 +0200 Subject: [PATCH 05/28] python:tests/dns_tkey: make use of self.assert_echoed_dns_error() Failed DNS updates just echo the request flaged as response, all other elements are unchanged. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 6e997f93d53ac45af79aec030bad73f51bdc5629) --- python/samba/tests/dns_tkey.py | 14 ++++---------- selftest/knownfail.d/dns_tkey | 2 ++ 2 files changed, 6 insertions(+), 10 deletions(-) create mode 100644 selftest/knownfail.d/dns_tkey diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index 42f73ba29214..a2544be35d10 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -65,7 +65,7 @@ class TestDNSUpdates(DNSTKeyTest): p = self.make_update_request() (response, response_p) = self.dns_transaction_udp(p, self.server_ip) - self.assert_dns_rcode_equals(response, dns.DNS_RCODE_REFUSED) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) @@ -78,10 +78,7 @@ class TestDNSUpdates(DNSTKeyTest): p = self.make_update_request() self.sign_packet(p, "badkey") (response, response_p) = self.dns_transaction_udp(p, self.server_ip) - self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTAUTH) - tsig_record = response.additional[0].rdata - self.assertEqual(tsig_record.error, dns.DNS_RCODE_BADKEY) - self.assertEqual(tsig_record.mac_size, 0) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) @@ -94,10 +91,7 @@ class TestDNSUpdates(DNSTKeyTest): p = self.make_update_request() self.bad_sign_packet(p, self.key_name) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) - self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTAUTH) - tsig_record = response.additional[0].rdata - self.assertEqual(tsig_record.error, dns.DNS_RCODE_BADSIG) - self.assertEqual(tsig_record.mac_size, 0) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) @@ -181,7 +175,7 @@ class TestDNSUpdates(DNSTKeyTest): p.answers = prereqs (response, response_p) = self.dns_transaction_udp(p, self.server_ip) - self.assert_dns_rcode_equals(response, dns.DNS_RCODE_REFUSED) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) self.tkey_trans() mac = self.sign_packet(p, self.key_name) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey new file mode 100644 index 000000000000..d2c8ff901830 --- /dev/null +++ b/selftest/knownfail.d/dns_tkey @@ -0,0 +1,2 @@ +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc -- 2.34.1 From 8094ec93d13c7b6e0df83a231689dc8bdbfe8a7a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:17:54 +0200 Subject: [PATCH 06/28] python:tests/dns_base: let tkey_trans() and sign_packet() take algorithm_name as argument BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit f8dfa9b33bdedffbe2e3b6e229ffae4beb3c712e) --- python/samba/tests/dns_base.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 909a9743691f..4a2893040656 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -248,7 +248,7 @@ class DNSTKeyTest(DNSTest): self.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) self.newrecname = "tkeytsig.%s" % self.get_dns_domain() - def tkey_trans(self, creds=None): + def tkey_trans(self, creds=None, algorithm_name="gss-tsig"): "Do a TKEY transaction and establish a gensec context" if creds is None: @@ -271,7 +271,7 @@ class DNSTKeyTest(DNSTest): r.ttl = 0 r.length = 0xffff rdata = dns.tkey_record() - rdata.algorithm = "gss-tsig" + rdata.algorithm = algorithm_name rdata.inception = int(time.time()) rdata.expiration = int(time.time()) + 60 * 60 rdata.mode = dns.DNS_TKEY_MODE_GSSAPI @@ -343,7 +343,9 @@ class DNSTKeyTest(DNSTest): data = request_mac + response_packet_wo_tsig + fake_tsig_packet self.g.check_packet(data, data, mac) - def sign_packet(self, packet, key_name, bad_sig=False): + def sign_packet(self, packet, key_name, + algorithm_name="gss-tsig", + bad_sig=False): "Sign a packet, calculate a MAC and add TSIG record" packet_data = ndr.ndr_pack(packet) @@ -353,7 +355,7 @@ class DNSTKeyTest(DNSTest): fake_tsig.ttl = 0 fake_tsig.time_prefix = 0 fake_tsig.time = int(time.time()) - fake_tsig.algorithm_name = "gss-tsig" + fake_tsig.algorithm_name = algorithm_name fake_tsig.fudge = 300 fake_tsig.error = 0 fake_tsig.other_size = 0 @@ -381,7 +383,7 @@ class DNSTKeyTest(DNSTest): mac_list[-1] = mac_list[-1] ^ 0xff rdata = dns.tsig_record() - rdata.algorithm_name = "gss-tsig" + rdata.algorithm_name = algorithm_name rdata.time_prefix = 0 rdata.time = fake_tsig.time rdata.fudge = 300 -- 2.34.1 From 6c64b8394589346babde1c0647d569edbb349f32 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 14:08:13 +0200 Subject: [PATCH 07/28] python:tests/dns_base: let tkey_trans() take tkey_req_in_answers It's possible to put the additional into the answers section, so we should be able to test that. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit cd747307d845f3cff723a7916aeeb31458f19202) --- python/samba/tests/dns_base.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 4a2893040656..41d34b0da36b 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -248,7 +248,8 @@ class DNSTKeyTest(DNSTest): self.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) self.newrecname = "tkeytsig.%s" % self.get_dns_domain() - def tkey_trans(self, creds=None, algorithm_name="gss-tsig"): + def tkey_trans(self, creds=None, algorithm_name="gss-tsig", + tkey_req_in_answers=False): "Do a TKEY transaction and establish a gensec context" if creds is None: @@ -297,8 +298,12 @@ class DNSTKeyTest(DNSTest): r.rdata = rdata additional = [r] - p.arcount = 1 - p.additional = additional + if tkey_req_in_answers: + p.ancount = 1 + p.answers = additional + else: + p.arcount = 1 + p.additional = additional (response, response_packet) =\ self.dns_transaction_tcp(p, self.server_ip) -- 2.34.1 From fa3c0e7e8db01b16f82ede1b0de1dcfd0c81e6c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 16:07:53 +0200 Subject: [PATCH 08/28] python:tests/dns_base: pass tkey_trans(expected_rcode) BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 27d92fa808c6617353c36fdb230504e880f4925b) --- python/samba/tests/dns_base.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 41d34b0da36b..01f980226846 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -249,7 +249,8 @@ class DNSTKeyTest(DNSTest): self.newrecname = "tkeytsig.%s" % self.get_dns_domain() def tkey_trans(self, creds=None, algorithm_name="gss-tsig", - tkey_req_in_answers=False): + tkey_req_in_answers=False, + expected_rcode=dns.DNS_RCODE_OK): "Do a TKEY transaction and establish a gensec context" if creds is None: @@ -307,6 +308,9 @@ class DNSTKeyTest(DNSTest): (response, response_packet) =\ self.dns_transaction_tcp(p, self.server_ip) + if expected_rcode != dns.DNS_RCODE_OK: + self.assert_echoed_dns_error(p, response, response_packet, expected_rcode) + return self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) tkey_record = response.answers[0].rdata -- 2.34.1 From d375a8aa6f6f06430251264265c94871ad415be7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 14:14:11 +0200 Subject: [PATCH 09/28] python:tests/dns_base: let dns_transaction_udp() take allow_{remaining,truncated}=True BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 1b1e7e06cf6ebd283de73c351267d53b42663d2f) --- python/samba/tests/dns_base.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 01f980226846..767d3f4170f6 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -130,6 +130,8 @@ class DNSTest(TestCaseInTempDir): return self.creds.get_realm().lower() def dns_transaction_udp(self, packet, host, + allow_remaining=False, + allow_truncated=False, dump=False, timeout=None): "send a DNS query and read the reply" s = None @@ -146,7 +148,17 @@ class DNSTest(TestCaseInTempDir): recv_packet = s.recv(2048, 0) if dump: print(self.hexdump(recv_packet)) - response = ndr.ndr_unpack(dns.name_packet, recv_packet) + if allow_truncated: + # with allow_remaining + # we add some zero bytes + # in order to also parse truncated + # responses + recv_packet_p = recv_packet + 32*b"\x00" + allow_remaining = True + else: + recv_packet_p = recv_packet + response = ndr.ndr_unpack(dns.name_packet, recv_packet_p, + allow_remaining=allow_remaining) return (response, recv_packet) finally: if s is not None: -- 2.34.1 From 849e424ae7d543eb0ec64a0bce6bb903a90d2669 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 14:10:52 +0200 Subject: [PATCH 10/28] python:tests/dns_base: maintain a dict with tkey related state This will allow tests to backup the whole state and mix them. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit b0af60e7850e656ef98edeac657c66b853080dab) --- python/samba/tests/dns_base.py | 40 ++++++++++++++++++++++------------ python/samba/tests/dns_tkey.py | 10 ++++----- python/samba/tests/join.py | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 767d3f4170f6..fbba1773ac5a 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -20,6 +20,7 @@ from samba.tests import TestCaseInTempDir from samba.dcerpc import dns, dnsp from samba import gensec, tests from samba import credentials +from samba import NTSTATUSError import struct import samba.ndr as ndr import random @@ -268,10 +269,16 @@ class DNSTKeyTest(DNSTest): if creds is None: creds = self.creds - self.key_name = "%s.%s" % (uuid.uuid4(), self.get_dns_domain()) + mech = 'spnego' + + tkey = {} + tkey['name'] = "%s.%s" % (uuid.uuid4(), self.get_dns_domain()) + tkey['creds'] = creds + tkey['mech'] = mech + tkey['algorithm'] = algorithm_name p = self.make_name_packet(dns.DNS_OPCODE_QUERY) - q = self.make_name_question(self.key_name, + q = self.make_name_question(tkey['name'], dns.DNS_QTYPE_TKEY, dns.DNS_QCLASS_IN) questions = [] @@ -279,7 +286,7 @@ class DNSTKeyTest(DNSTest): self.finish_name_packet(p, questions) r = dns.res_rec() - r.name = self.key_name + r.name = tkey['name'] r.rr_type = dns.DNS_QTYPE_TKEY r.rr_class = dns.DNS_QCLASS_IN r.ttl = 0 @@ -292,17 +299,17 @@ class DNSTKeyTest(DNSTest): rdata.error = 0 rdata.other_size = 0 - self.g = gensec.Security.start_client(self.settings) - self.g.set_credentials(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") + tkey['gensec'] = gensec.Security.start_client(self.settings) + tkey['gensec'].set_credentials(creds) + tkey['gensec'].set_target_service("dns") + tkey['gensec'].set_target_hostname(self.server) + tkey['gensec'].want_feature(gensec.FEATURE_SIGN) + tkey['gensec'].start_mech_by_name(tkey['mech']) finished = False client_to_server = b"" - (finished, server_to_client) = self.g.update(client_to_server) + (finished, server_to_client) = tkey['gensec'].update(client_to_server) self.assertFalse(finished) data = [x if isinstance(x, int) else ord(x) for x in list(server_to_client)] @@ -327,9 +334,11 @@ class DNSTKeyTest(DNSTest): tkey_record = response.answers[0].rdata server_to_client = bytes(tkey_record.key_data) - (finished, client_to_server) = self.g.update(server_to_client) + (finished, client_to_server) = tkey['gensec'].update(server_to_client) self.assertTrue(finished) + self.tkey = tkey + self.verify_packet(response, response_packet) def verify_packet(self, response, response_packet, request_mac=b""): @@ -349,7 +358,7 @@ class DNSTKeyTest(DNSTest): response_packet_wo_tsig = ndr.ndr_pack(response_copy) fake_tsig = dns.fake_tsig_rec() - fake_tsig.name = self.key_name + fake_tsig.name = self.tkey['name'] fake_tsig.rr_class = dns.DNS_QCLASS_ANY fake_tsig.ttl = 0 fake_tsig.time_prefix = tsig_record.time_prefix @@ -362,7 +371,10 @@ class DNSTKeyTest(DNSTest): 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) + try: + self.tkey['gensec'].check_packet(data, data, mac) + except NTSTATUSError as nt: + raise AssertionError(nt) def sign_packet(self, packet, key_name, algorithm_name="gss-tsig", @@ -383,7 +395,7 @@ class DNSTKeyTest(DNSTest): fake_tsig_packet = ndr.ndr_pack(fake_tsig) data = packet_data + fake_tsig_packet - mac = self.g.sign_packet(data, data) + mac = self.tkey['gensec'].sign_packet(data, data) mac_list = [x if isinstance(x, int) else ord(x) for x in list(mac)] if bad_sig: if len(mac) > 8: diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index a2544be35d10..4c56722cfd74 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -89,7 +89,7 @@ class TestDNSUpdates(DNSTKeyTest): self.tkey_trans() p = self.make_update_request() - self.bad_sign_packet(p, self.key_name) + self.bad_sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) @@ -102,7 +102,7 @@ class TestDNSUpdates(DNSTKeyTest): self.tkey_trans() p = self.make_update_request() - mac = self.sign_packet(p, self.key_name) + mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) @@ -113,7 +113,7 @@ class TestDNSUpdates(DNSTKeyTest): # Now delete the record p = self.make_update_request(delete=True) - mac = self.sign_packet(p, self.key_name) + mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) @@ -178,7 +178,7 @@ class TestDNSUpdates(DNSTKeyTest): self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) self.tkey_trans() - mac = self.sign_packet(p, self.key_name) + mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) @@ -189,7 +189,7 @@ class TestDNSUpdates(DNSTKeyTest): # Now delete the record p = self.make_update_request(delete=True) - mac = self.sign_packet(p, self.key_name) + mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) diff --git a/python/samba/tests/join.py b/python/samba/tests/join.py index da34171da280..f5e229075c92 100644 --- a/python/samba/tests/join.py +++ b/python/samba/tests/join.py @@ -156,7 +156,7 @@ class JoinTestCase(DNSTKeyTest): p.nscount = len(updates) p.nsrecs = updates - mac = self.sign_packet(p, self.key_name) + mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) -- 2.34.1 From 89b14b04a5945d3ee3202987632fe73731537c1e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 16:41:12 +0200 Subject: [PATCH 11/28] python:tests/dns_tkey: test TKEY with gss-tsig, gss.microsoft.com and invalid algorithms BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 740bda87a80b97816d892e8f7aae28759f6916ec) --- python/samba/tests/dns_tkey.py | 21 +++++++++++++++++++-- selftest/knownfail.d/dns_tkey | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index 4c56722cfd74..6d6bbd4973d3 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -55,11 +55,28 @@ class TestDNSUpdates(DNSTKeyTest): self.server_ip = server_ip super(TestDNSUpdates, self).setUp() - def test_tkey(self): - "test DNS TKEY handshake" + def test_tkey_gss_tsig(self): + "test DNS TKEY handshake with gss-tsig" self.tkey_trans() + def test_tkey_gss_microsoft_com(self): + "test DNS TKEY handshake with gss.microsoft.com" + + self.tkey_trans(algorithm_name="gss.microsoft.com") + + def test_tkey_invalid_gss_TSIG(self): + "test DNS TKEY handshake with invalid gss-TSIG" + + self.tkey_trans(algorithm_name="gss-TSIG", + expected_rcode=dns.DNS_RCODE_REFUSED) + + def test_tkey_invalid_gss_MICROSOFT_com(self): + "test DNS TKEY handshake with invalid gss.MICROSOFT.com" + + self.tkey_trans(algorithm_name="gss.MICROSOFT.com", + expected_rcode=dns.DNS_RCODE_REFUSED) + def test_update_wo_tsig(self): "test DNS update without TSIG record" diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index d2c8ff901830..fb0fca9ec58a 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -1,2 +1,5 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_gss_microsoft_com.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_MICROSOFT_com.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_TSIG.fl2008r2dc -- 2.34.1 From 32f88d82317cad373da1a0db7958a44b816ccf02 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 14:15:45 +0200 Subject: [PATCH 12/28] python:tests/dns_tkey: let us have test_update_gss_tsig_tkey_req_{additional,answers}() Also test using the additional record in the answers section. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 3c7cb85eaf8371be55a371601cc354440dab7a94) --- python/samba/tests/dns_base.py | 8 ++++++++ python/samba/tests/dns_tkey.py | 30 ++++++++++++++++++++++++++++-- selftest/knownfail.d/dns_tkey | 1 + 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index fbba1773ac5a..b8afc1f22a2f 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -161,6 +161,10 @@ class DNSTest(TestCaseInTempDir): response = ndr.ndr_unpack(dns.name_packet, recv_packet_p, allow_remaining=allow_remaining) return (response, recv_packet) + except RuntimeError as re: + if s is not None: + s.close() + raise AssertionError(re) finally: if s is not None: s.close() @@ -198,6 +202,10 @@ class DNSTest(TestCaseInTempDir): print(self.hexdump(recv_packet)) response = ndr.ndr_unpack(dns.name_packet, recv_packet[2:]) + except RuntimeError as re: + if s is not None: + s.close() + raise AssertionError(re) finally: if s is not None: s.close() diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index 6d6bbd4973d3..04cab75aa708 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -113,8 +113,8 @@ class TestDNSUpdates(DNSTKeyTest): rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) - def test_update_tsig(self): - "test DNS update with correct TSIG record" + def test_update_gss_tsig_tkey_req_additional(self): + "test DNS update with correct gss-tsig record tkey req in additional" self.tkey_trans() @@ -139,6 +139,32 @@ class TestDNSUpdates(DNSTKeyTest): rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_gss_tsig_tkey_req_answers(self): + "test DNS update with correct gss-tsig record tsig req in answers" + + self.tkey_trans(tkey_req_in_answers=True) + + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # check it's gone + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_tsig_windows(self): "test DNS update with correct TSIG record (follow Windows pattern)" diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index fb0fca9ec58a..141a3a405e3a 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -3,3 +3,4 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_gss_microsoft_com.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_MICROSOFT_com.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_TSIG.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc -- 2.34.1 From 47fecde26abc184e3a112452da1ee1e03dfef1bb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 17:18:34 +0200 Subject: [PATCH 13/28] python:tests/dns_tkey: add gss.microsoft.com tsig updates BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit b9b03ca503c43c7ee06df6c331839bd47f9eac8c) --- python/samba/tests/dns_tkey.py | 59 ++++++++++++++++++++++++++++++++++ selftest/knownfail.d/dns_tkey | 2 ++ 2 files changed, 61 insertions(+) diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index 04cab75aa708..4874d48e9cb6 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -165,6 +165,65 @@ class TestDNSUpdates(DNSTKeyTest): rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_gss_microsoft_com_tkey_req_additional(self): + "test DNS update with correct gss.microsoft.com record tsig req in additional" + + algorithm_name = "gss.microsoft.com" + self.tkey_trans(algorithm_name=algorithm_name) + + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # check it's gone + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + + def test_update_gss_microsoft_com_tkey_req_answers(self): + "test DNS update with correct gss.microsoft.com record tsig req in answers" + + algorithm_name = "gss.microsoft.com" + self.tkey_trans(algorithm_name=algorithm_name, + tkey_req_in_answers=True) + + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # check it's gone + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_tsig_windows(self): "test DNS update with correct TSIG record (follow Windows pattern)" diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 141a3a405e3a..9c7c5ce71cd4 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -4,3 +4,5 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_MICROSOFT_com.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_TSIG.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_additional.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_answers.fl2008r2dc -- 2.34.1 From adab5d38a6c831ba6facb57c7ccfcfa94ef40350 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 17:26:39 +0200 Subject: [PATCH 14/28] python:tests/dns_tkey: test bad and changing tsig algorithms BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit de4ed363d378f2065a4634f94af80ea0e3965c96) --- python/samba/tests/dns_tkey.py | 104 +++++++++++++++++++++++++++++++++ selftest/knownfail.d/dns_tkey | 3 + 2 files changed, 107 insertions(+) diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index 4874d48e9cb6..e77aa4088a64 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -19,6 +19,7 @@ import sys import optparse import samba.getopt as options +import samba.ndr as ndr from samba.dcerpc import dns from samba.tests.subunitrun import SubunitOptions, TestProgram from samba.tests.dns_base import DNSTKeyTest @@ -113,6 +114,109 @@ class TestDNSUpdates(DNSTKeyTest): rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_tsig_bad_algorithm(self): + "test DNS update with a TSIG record with a bad algorithm" + + self.tkey_trans() + + algorithm_name = "gss-TSIG" + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) + + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + + def test_update_tsig_changed_algorithm1(self): + "test DNS update with a TSIG record with a changed algorithm" + + algorithm_name = "gss-tsig" + self.tkey_trans(algorithm_name=algorithm_name) + + # Now delete the record, it's most likely + # a no-op as it should not be there if the test + # runs the first time + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Now do an update with the algorithm_name + # changed in the requests TSIG message. + p = self.make_update_request() + algorithm_name = "gss.microsoft.com" + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + algorithm_name = "gss-tsig" + (response, response_p) = self.dns_transaction_udp(p, self.server_ip, + allow_remaining=True) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record, with the original + # algorithm_name used in the tkey exchange + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + + def test_update_tsig_changed_algorithm2(self): + "test DNS update with a TSIG record with a changed algorithm" + + algorithm_name = "gss.microsoft.com" + self.tkey_trans(algorithm_name=algorithm_name) + + # Now delete the record, it's most likely + # a no-op as it should not be there if the test + # runs the first time + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Now do an update with the algorithm_name + # changed in the requests TSIG message. + p = self.make_update_request() + algorithm_name = "gss-tsig" + mac = self.sign_packet(p, self.tkey['name'], + algorithm_name=algorithm_name) + algorithm_name = "gss.microsoft.com" + (response, response_p) = self.dns_transaction_udp(p, self.server_ip, + allow_truncated=True) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + response_p_pack = ndr.ndr_pack(response) + if len(response_p_pack) == len(response_p): + self.verify_packet(response, response_p, mac) + else: + pass # Windows bug + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record, with the original + # algorithm_name used in the tkey exchange + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_gss_tsig_tkey_req_additional(self): "test DNS update with correct gss-tsig record tkey req in additional" diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 9c7c5ce71cd4..f1889609e6d3 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -6,3 +6,6 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_answers.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_algorithm.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm1.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm2.fl2008r2dc -- 2.34.1 From 7f94aac033ec0e3e8912edf62e9b88a27c55a32d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:17:54 +0200 Subject: [PATCH 15/28] python:tests/dns_base: let verify_packet() work against Windows BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 8324d0739dfdd0a081c403e298a9038ee7df681f) --- python/samba/tests/dns_base.py | 11 ++++++++++- selftest/knownfail.d/dns_tkey | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index b8afc1f22a2f..3d751faee5cf 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -353,6 +353,15 @@ class DNSTKeyTest(DNSTest): self.assertEqual(response.arcount, 1) self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG) + if self.tkey['algorithm'] == "gss-tsig": + gss_tsig = True + else: + gss_tsig = False + + request_mac_len = b"" + if len(request_mac) > 0 and gss_tsig: + request_mac_len = struct.pack('!H', len(request_mac)) + tsig_record = response.additional[0].rdata mac = bytes(tsig_record.mac) @@ -378,7 +387,7 @@ class DNSTKeyTest(DNSTest): fake_tsig.other_data = tsig_record.other_data fake_tsig_packet = ndr.ndr_pack(fake_tsig) - data = request_mac + response_packet_wo_tsig + fake_tsig_packet + data = request_mac_len + request_mac + response_packet_wo_tsig + fake_tsig_packet try: self.tkey['gensec'].check_packet(data, data, mac) except NTSTATUSError as nt: diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index f1889609e6d3..19fe5c8bde3a 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -9,3 +9,5 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_algorithm.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm1.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm2.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc -- 2.34.1 From febb3c8803dc8f0e5cd5bb1f9b7845707d9ff6df Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 13:17:54 +0200 Subject: [PATCH 16/28] python:tests/dns_tkey: let test_update_tsig_windows() actually pass against windows 2022 BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 848318338b2972f331e067bf1c8d6c7dac0748c8) --- python/samba/tests/dns_tkey.py | 32 ++++++++++++++++++-------------- selftest/knownfail.d/dns_tkey | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index e77aa4088a64..a88c30a6754f 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -331,35 +331,28 @@ class TestDNSUpdates(DNSTKeyTest): def test_update_tsig_windows(self): "test DNS update with correct TSIG record (follow Windows pattern)" - newrecname = "win" + self.newrecname + p = self.make_update_request() + rr_class = dns.DNS_QCLASS_IN ttl = 1200 - p = self.make_name_packet(dns.DNS_OPCODE_UPDATE) - q = self.make_name_question(self.get_dns_domain(), - dns.DNS_QTYPE_SOA, - dns.DNS_QCLASS_IN) - questions = [] - questions.append(q) - self.finish_name_packet(p, questions) - updates = [] r = dns.res_rec() - r.name = newrecname + r.name = self.newrecname r.rr_type = dns.DNS_QTYPE_A r.rr_class = dns.DNS_QCLASS_ANY r.ttl = 0 r.length = 0 updates.append(r) r = dns.res_rec() - r.name = newrecname + r.name = self.newrecname r.rr_type = dns.DNS_QTYPE_AAAA r.rr_class = dns.DNS_QCLASS_ANY r.ttl = 0 r.length = 0 updates.append(r) r = dns.res_rec() - r.name = newrecname + r.name = self.newrecname r.rr_type = dns.DNS_QTYPE_A r.rr_class = rr_class r.ttl = ttl @@ -371,7 +364,7 @@ class TestDNSUpdates(DNSTKeyTest): prereqs = [] r = dns.res_rec() - r.name = newrecname + r.name = self.newrecname r.rr_type = dns.DNS_QTYPE_CNAME r.rr_class = dns.DNS_QCLASS_NONE r.ttl = 0 @@ -390,11 +383,22 @@ class TestDNSUpdates(DNSTKeyTest): self.verify_packet(response, response_p, mac) # Check the record is around - rcode = self.search_record(newrecname) + rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) # Now delete the record + delete_updates = [] + r = dns.res_rec() + r.name = self.newrecname + r.rr_type = dns.DNS_QTYPE_A + r.rr_class = dns.DNS_QCLASS_NONE + r.ttl = 0 + r.length = 0xffff + r.rdata = "10.1.45.64" + delete_updates.append(r) p = self.make_update_request(delete=True) + p.nscount = len(delete_updates) + p.nsrecs = delete_updates mac = self.sign_packet(p, self.tkey['name']) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 19fe5c8bde3a..30dbcb2bff61 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -11,3 +11,4 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm2.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_wo_tsig.fl2008r2dc -- 2.34.1 From c8a9a87dd06ca1cc0b24497946837d34abb9ea65 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 11:39:56 +0200 Subject: [PATCH 17/28] python:tests/dns_base: add get_unpriv_creds() helper BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 88457da00d4110b419f7a7ccabcd542fa77e463f) --- python/samba/tests/dns_base.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py index 3d751faee5cf..79c73b37a950 100644 --- a/python/samba/tests/dns_base.py +++ b/python/samba/tests/dns_base.py @@ -267,8 +267,23 @@ class DNSTKeyTest(DNSTest): 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.unpriv_creds = None + self.newrecname = "tkeytsig.%s" % self.get_dns_domain() + def get_unpriv_creds(self): + if self.unpriv_creds is not None: + return self.unpriv_creds + + self.unpriv_creds = credentials.Credentials() + self.unpriv_creds.guess(self.lp_ctx) + self.unpriv_creds.set_username(tests.env_get_var_value('USERNAME_UNPRIV')) + self.unpriv_creds.set_password(tests.env_get_var_value('PASSWORD_UNPRIV')) + self.unpriv_creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) + + return self.unpriv_creds + def tkey_trans(self, creds=None, algorithm_name="gss-tsig", tkey_req_in_answers=False, expected_rcode=dns.DNS_RCODE_OK): -- 2.34.1 From fc56e79b4806fc312b005529cd5c5cc9a81fd77f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 11:39:56 +0200 Subject: [PATCH 18/28] s4:selftest/tests: pass USERNAME_UNPRIV=$DOMAIN_USER to samba.tests.dns_tkey BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 753428a3b6c488c4aacea04d2ddb9ea73244695a) --- source4/selftest/tests.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 8456ec1f1c58..ff53ae8c2a29 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -510,7 +510,11 @@ plantestsuite_loadlist("samba.tests.dns_aging", "fl2003dc:local", plantestsuite_loadlist("samba.tests.dns_forwarder", "fl2003dc:local", [python, os.path.join(srcdir(), "python/samba/tests/dns_forwarder.py"), '$SERVER', '$SERVER_IP', '$DNS_FORWARDER1', '$DNS_FORWARDER2', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) -plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) +plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", + ['USERNAME_UNPRIV=$DOMAIN_USER','PASSWORD_UNPRIV=$DOMAIN_USER_PASSWORD', + python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), + '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', + '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba.tests.dns_wildcard", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_wildcard.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba.tests.dns_invalid", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_invalid.py"), '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) -- 2.34.1 From a62bf5118dfb8ab5736eb65b47da0c29ae62d89d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 29 May 2024 11:40:51 +0200 Subject: [PATCH 19/28] python:tests/dns_tkey: add test_update_tsig_record_access_denied() This demonstrates that access_denied is only generated if the client really generates a change in the database. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 708a6fae6978e1462e1a53f4ee08f11b51a5637a) --- python/samba/tests/dns_tkey.py | 55 ++++++++++++++++++++++++++++++++++ selftest/knownfail.d/dns_tkey | 1 + 2 files changed, 56 insertions(+) diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py index a88c30a6754f..694ad22b4e4f 100644 --- a/python/samba/tests/dns_tkey.py +++ b/python/samba/tests/dns_tkey.py @@ -408,5 +408,60 @@ class TestDNSUpdates(DNSTKeyTest): rcode = self.search_record(self.newrecname) self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + def test_update_tsig_record_access_denied(self): + """test DNS update with a TSIG record where the user does not have + permissions to change the record""" + + self.tkey_trans() + adm_tkey = self.tkey + + # First create the record as admin + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now update the same values as normal user + # should work without error + self.tkey_trans(creds=self.get_unpriv_creds()) + unpriv_tkey = self.tkey + + p = self.make_update_request() + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # Check the record is still around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now try to delete the record a normal user (should fail) + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED) + + # Check the record is still around + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK) + + # Now delete the record as admin + self.tkey = adm_tkey + p = self.make_update_request(delete=True) + mac = self.sign_packet(p, self.tkey['name']) + (response, response_p) = self.dns_transaction_udp(p, self.server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.verify_packet(response, response_p, mac) + + # check it's gone + rcode = self.search_record(self.newrecname) + self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN) + TestProgram(module=__name__, opts=subunitopts) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 30dbcb2bff61..0925ca288a1f 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -12,3 +12,4 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_wo_tsig.fl2008r2dc +^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_record_access_denied.fl2008r2dc -- 2.34.1 From 16618b957cdf26978d84106e38f641308eb30cc9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:36:40 +0200 Subject: [PATCH 20/28] s4:dns_server: failed dns updates should result in REFUSED for ACCESS_DENIED BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit a56627b0d125ef7b456bebe307087f324f1f0422) --- source4/dns_server/dnsserver_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 0481b0715c7f..d7774d0eb30e 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -68,6 +68,8 @@ uint8_t werr_to_dns_err(WERROR werr) return DNS_RCODE_NOTZONE; } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) { return DNS_RCODE_BADKEY; + } else if (W_ERROR_EQUAL(WERR_ACCESS_DENIED, werr)) { + return DNS_RCODE_REFUSED; } DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr))); return DNS_RCODE_SERVFAIL; -- 2.34.1 From 995c00445bae62b71fd41dba71c2b20c169ff812 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:38:24 +0200 Subject: [PATCH 21/28] s4:dns_server: only allow gss-tsig and gss.microsoft.com for TKEY BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit fa0f23e69eaf4f475bc9dc9aa0e23c7bd5208250) --- selftest/knownfail.d/dns_tkey | 2 -- source4/dns_server/dns_query.c | 11 ++++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 0925ca288a1f..edb6e0b21152 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -1,8 +1,6 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_gss_microsoft_com.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_MICROSOFT_com.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_invalid_gss_TSIG.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_answers.fl2008r2dc diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 181beda219b5..3ac3cd4b2b19 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -663,8 +663,17 @@ static NTSTATUS create_tkey(struct dns_server *dns, { NTSTATUS status; struct dns_server_tkey_store *store = dns->tkeys; - struct dns_server_tkey *k = talloc_zero(store, struct dns_server_tkey); + struct dns_server_tkey *k = NULL; + + if (strcmp(algorithm, "gss-tsig") == 0) { + /* ok */ + } else if (strcmp(algorithm, "gss.microsoft.com") == 0) { + /* ok */ + } else { + return NT_STATUS_ACCESS_DENIED; + } + k = talloc_zero(store, struct dns_server_tkey); if (k == NULL) { return NT_STATUS_NO_MEMORY; } -- 2.34.1 From 30b5934d7345f2906aa55b5eeb21daef5ae632c8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:38:24 +0200 Subject: [PATCH 22/28] s4:dns_server: only allow gss-tsig and gss.microsoft.com for TSIG BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 3467d1491490830d61d16cb6278051daf48466fc) --- source4/dns_server/dns_crypto.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c index be79a4e87b75..332d2255dd43 100644 --- a/source4/dns_server/dns_crypto.c +++ b/source4/dns_server/dns_crypto.c @@ -106,7 +106,7 @@ WERROR dns_verify_tsig(struct dns_server *dns, struct dns_server_tkey *tkey = NULL; struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); - + const char *algorithm = NULL; /* Find the first TSIG record in the additional records */ for (i=0; i < packet->arcount; i++) { @@ -161,6 +161,16 @@ WERROR dns_verify_tsig(struct dns_server *dns, } DBG_DEBUG("dns_find_tkey() => found\n"); + algorithm = state->tsig->rdata.tsig_record.algorithm_name; + if (strcmp(algorithm, "gss-tsig") == 0) { + /* ok */ + } else if (strcmp(algorithm, "gss.microsoft.com") == 0) { + /* ok */ + } else { + state->tsig_error = DNS_RCODE_BADKEY; + return DNS_ERR(REFUSED); + } + /* * Remember the keyname that found an existing tkey, used * later to fetch the key with dns_find_tkey() when signing -- 2.34.1 From e38265bcdc0bfb6208ee4f1fca79972bca26281d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:38:24 +0200 Subject: [PATCH 23/28] s4:dns_server: use the client provided algorithm for the fake TSIG structure BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit bd0235cd515d5602ed9501bfc810a2487364ea10) --- source4/dns_server/dns_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c index 332d2255dd43..9d44512b1cad 100644 --- a/source4/dns_server/dns_crypto.c +++ b/source4/dns_server/dns_crypto.c @@ -193,7 +193,7 @@ WERROR dns_verify_tsig(struct dns_server *dns, } check_rec->rr_class = DNS_QCLASS_ANY; check_rec->ttl = 0; - check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm); + check_rec->algorithm_name = talloc_strdup(check_rec, algorithm); if (check_rec->algorithm_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } -- 2.34.1 From 27625dceca2151dc28db4c9726608cf6f85ea199 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 31 May 2024 08:38:24 +0200 Subject: [PATCH 24/28] s4:dns_server: use tkey->algorithm if available in dns_sign_tsig() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit ae7538af04435658d2ba6dcab109beecb6c5f13e) --- selftest/knownfail.d/dns_tkey | 3 --- source4/dns_server/dns_crypto.c | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index edb6e0b21152..8ce60f8507c5 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -1,12 +1,9 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_tkey_gss_microsoft_com.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_answers.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_algorithm.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm1.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm2.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_wo_tsig.fl2008r2dc diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c index 9d44512b1cad..19d6b0dad14b 100644 --- a/source4/dns_server/dns_crypto.c +++ b/source4/dns_server/dns_crypto.c @@ -382,6 +382,7 @@ WERROR dns_sign_tsig(struct dns_server *dns, .data = NULL, .length = 0 }; + const char *algorithm = "gss-tsig"; tsig = talloc_zero(mem_ctx, struct dns_res_rec); if (tsig == NULL) { @@ -402,6 +403,8 @@ WERROR dns_sign_tsig(struct dns_server *dns, if (!W_ERROR_IS_OK(werror)) { return werror; } + + algorithm = tkey->algorithm; } tsig->name = talloc_strdup(tsig, state->key_name); @@ -412,7 +415,7 @@ WERROR dns_sign_tsig(struct dns_server *dns, tsig->rr_type = DNS_QTYPE_TSIG; tsig->ttl = 0; tsig->length = UINT16_MAX; - tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig"); + tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, algorithm); if (tsig->rdata.tsig_record.algorithm_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } -- 2.34.1 From 9080d80065314a54085b6128ddc2249f115235d9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 30 May 2024 14:41:21 +0200 Subject: [PATCH 25/28] s4:dns_server: also search DNS_QTYPE_TKEY in the answers section if it's the last section BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 5906ed94f2c5c68e83c63e7c201534eeb323cfe7) --- selftest/knownfail.d/dns_tkey | 1 - source4/dns_server/dns_query.c | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 8ce60f8507c5..12c38d83b972 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -1,7 +1,6 @@ ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_microsoft_com_tkey_req_answers.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_algorithm.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm1.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 3ac3cd4b2b19..1f46ee0aa197 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -799,12 +799,22 @@ static WERROR handle_tkey(struct dns_server *dns, { struct dns_res_rec *in_tkey = NULL; struct dns_res_rec *ret_tkey; - uint16_t i; - for (i = 0; i < in->arcount; i++) { + /* + * TKEY needs to we the last one in + * additional or answers + */ + if (in->arcount >= 1) { + uint16_t i = in->arcount - 1; if (in->additional[i].rr_type == DNS_QTYPE_TKEY) { in_tkey = &in->additional[i]; - break; + } + } else if (in->nscount >= 1) { + /* no lookup */ + } else if (in->ancount >= 1) { + uint16_t i = in->ancount - 1; + if (in->answers[i].rr_type == DNS_QTYPE_TKEY) { + in_tkey = &in->answers[i]; } } -- 2.34.1 From c6b87f62a8acbe8c547a7482fd5e87f24b5218ee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 30 May 2024 14:42:53 +0200 Subject: [PATCH 26/28] s4:dns_server: dns_verify_tsig should return REFUSED on error BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit db350bc573b378fb0615bdd8592cc9c62f6db146) --- source4/dns_server/dns_crypto.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c index 19d6b0dad14b..f9b3bd161c52 100644 --- a/source4/dns_server/dns_crypto.c +++ b/source4/dns_server/dns_crypto.c @@ -145,7 +145,7 @@ WERROR dns_verify_tsig(struct dns_server *dns, tkey = dns_find_tkey(dns->tkeys, state->tsig->name); if (tkey == NULL) { - DBG_DEBUG("dns_find_tkey() => NOTAUTH / DNS_RCODE_BADKEY\n"); + DBG_DEBUG("dns_find_tkey() => REFUSED / DNS_RCODE_BADKEY\n"); /* * We must save the name for use in the TSIG error * response and have no choice here but to save the @@ -157,7 +157,7 @@ WERROR dns_verify_tsig(struct dns_server *dns, return WERR_NOT_ENOUGH_MEMORY; } state->tsig_error = DNS_RCODE_BADKEY; - return DNS_ERR(NOTAUTH); + return DNS_ERR(REFUSED); } DBG_DEBUG("dns_find_tkey() => found\n"); @@ -249,7 +249,7 @@ WERROR dns_verify_tsig(struct dns_server *dns, dump_data_dbgc(DBGC_DNS, 8, buffer, buffer_len); DBG_NOTICE("Verifying tsig failed: %s\n", nt_errstr(status)); state->tsig_error = DNS_RCODE_BADSIG; - return DNS_ERR(NOTAUTH); + return DNS_ERR(REFUSED); } if (!NT_STATUS_IS_OK(status)) { -- 2.34.1 From a56c7a673903cd0d933a7a5fbc283520f35a62c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 30 May 2024 14:39:28 +0200 Subject: [PATCH 27/28] s4:dns_server: correctly sign dns update responses with gss-tsig like Windows This means we no longer generate strange errors/warnings in the Windows event log nor in the nsupdate -g output. Note: this is a only difference between gss-tsig and the legacy gss.microsoft.com algorithms. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 76fec2668e73b9d15447abee551d5c04148aaf27) --- selftest/knownfail.d/dns_tkey | 6 ------ source4/dns_server/dns_crypto.c | 24 +++++++++++++++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey index 12c38d83b972..a88b7cf3e8c6 100644 --- a/selftest/knownfail.d/dns_tkey +++ b/selftest/knownfail.d/dns_tkey @@ -1,9 +1,3 @@ -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_keyname.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_mac.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_answers.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_bad_algorithm.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_changed_algorithm1.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_gss_tsig_tkey_req_additional.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_wo_tsig.fl2008r2dc ^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_record_access_denied.fl2008r2dc diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c index f9b3bd161c52..d30e97150863 100644 --- a/source4/dns_server/dns_crypto.c +++ b/source4/dns_server/dns_crypto.c @@ -27,6 +27,7 @@ #include "libcli/util/ntstatus.h" #include "auth/auth.h" #include "auth/gensec/gensec.h" +#include "lib/util/bytearray.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS @@ -281,11 +282,19 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx, struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); size_t mac_size = 0; + bool gss_tsig; if (check_rec == NULL) { return WERR_NOT_ENOUGH_MEMORY; } + if (strcmp(tkey->algorithm, "gss-tsig") == 0) { + gss_tsig = true; + } else { + /* gss.microsoft.com */ + gss_tsig = false; + } + /* first build and verify check packet */ check_rec->name = talloc_strdup(check_rec, tkey->name); if (check_rec->name == NULL) { @@ -325,6 +334,9 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx, } buffer_len = mac_size; + if (gss_tsig && mac_size > 0) { + buffer_len += 2; + } buffer_len += packet_blob.length; if (buffer_len < packet_blob.length) { @@ -345,11 +357,21 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx, /* * RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer * that we're going to sign: - * 1. MAC of request (if present) + * 1. if MAC of request is present + * - 16bit big endian length of MAC of request + * - MAC of request * 2. Outgoing packet * 3. TSIG record */ if (mac_size > 0) { + if (gss_tsig) { + /* + * only gss-tsig not with + * gss.microsoft.com + */ + PUSH_BE_U16(p, 0, mac_size); + p += 2; + } memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size); p += mac_size; } -- 2.34.1 From 051ca96ef76971e6a4ae28d2534bf6475f93080a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 30 May 2024 14:52:22 +0200 Subject: [PATCH 28/28] s4:dns_server: no-op dns updates with ACCESS_DENIED should be ignored If the client does not have permissions to update the record, but the record already has the data the update tries to apply, it's a no-op that should result in success instead of failing. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13019 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Jun 6 03:18:16 UTC 2024 on atb-devel-224 (cherry picked from commit ed61c57e02309b738e73fb12877a0a565b627724) --- selftest/knownfail.d/dns_tkey | 3 --- source4/dns_server/dns_update.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) delete mode 100644 selftest/knownfail.d/dns_tkey diff --git a/selftest/knownfail.d/dns_tkey b/selftest/knownfail.d/dns_tkey deleted file mode 100644 index a88b7cf3e8c6..000000000000 --- a/selftest/knownfail.d/dns_tkey +++ /dev/null @@ -1,3 +0,0 @@ -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_windows.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_wo_tsig.fl2008r2dc -^samba.tests.dns_tkey.__main__.TestDNSUpdates.test_update_tsig_record_access_denied.fl2008r2dc diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index 3cc26952353a..dc13a24609b5 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -570,6 +570,8 @@ static WERROR handle_one_update(struct dns_server *dns, W_ERROR_NOT_OK_RETURN(werror); for (i = first; i < rcount; i++) { + struct dnsp_DnssrvRpcRecord orig_rec = recs[i]; + if (!dns_record_match(&recs[i], &recs[rcount])) { continue; } @@ -583,6 +585,15 @@ static WERROR handle_one_update(struct dns_server *dns, werror = dns_replace_records(dns, mem_ctx, dn, needs_add, recs, rcount); DBG_DEBUG("dns_replace_records(REPLACE): %s\n", win_errstr(werror)); + if (W_ERROR_EQUAL(werror, WERR_ACCESS_DENIED) && + !needs_add && + orig_rec.dwTtlSeconds == recs[i].dwTtlSeconds) + { + DBG_NOTICE("dns_replace_records(REPLACE): %s " + "=> skip no-op\n", + win_errstr(werror)); + werror = WERR_OK; + } W_ERROR_NOT_OK_RETURN(werror); return WERR_OK; -- 2.34.1