[Pkg-samba-maint] [Git][samba-team/samba][stretch] 11 commits: CVE-2018-14629 dns: fix CNAME loop prevention using counter regression

Mathieu Parent gitlab at salsa.debian.org
Fri Jan 18 06:40:09 GMT 2019


Mathieu Parent pushed to branch stretch at Debian Samba Team / samba


Commits:
3ffbc913 by Stefan Metzmacher at 2019-01-17T21:16:14Z
CVE-2018-14629 dns: fix CNAME loop prevention using counter regression

The loop prevention should only be done for CNAME records!

Otherwise we truncate the answer records for A, AAAA or
SRV queries, which is a bad idea if you have more than 20 DCs.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>

- - - - -
16ba2723 by Aaron Haslett at 2019-01-17T21:16:14Z
CVE-2018-14629: Tests to expose regression from dns cname loop fix

These tests expose the regression described by Stefan Metzmacher in
discussion on the bugzilla paged linked below.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13600
Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>

- - - - -
7f390336 by Mathieu Parent at 2019-01-17T21:16:14Z
Add patches for CVE-2018-14629 regression fix

"The patches introduce a regression, when there're more than 20 records on
a non CNAME record.

This happens in domains with more than 20 DCs."

- - - - -
97a53c7b by Anoop C S at 2019-01-17T21:16:15Z
s3/libsmb: Explicitly set delete_on_close token for rmdir

The current implementation of `rmdir` hopes to get the directory deleted
on closing last open handle when FILE_DELETE_ON_CLOSE is set on it. But
for non-empty directories Windows doesn't error out during an open call.
Following that we internally refuse to set initial delete_on_close while
opening a non-empty directory. This prevents us from trying to delete
the directory when last open handle is closed.

Instead of relying on FILE_DELETE_ON_CLOSE during an open we explicitly
set delete_on_close token on directory handle once it is available. This
ensures that NT_STATUS_DIRECTORY_NOT_EMPTY is returned for `rmdir` on
non-empty directories while closing open directory handle.

Applied-Upstream: https://github.com/samba-team/samba/commit/6b68e3eca631c04d6d57c489daf60f64732fc86d
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13204
Bug-Debian: https://bugs.debian.org/915248
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/samba/+bug/1795772

- - - - -
c9b94ccf by Mathieu Parent at 2019-01-17T21:16:15Z
Fix rmdir on non-empty samba directory (Closes: #915248)

- - - - -
b5331be2 by Mathieu Parent at 2019-01-17T21:16:15Z
Ignore nmbd start errors when there is no non-loopback interface (Closes: #893762)

(cherry picked from commit f175f540fb26aa1f9193322874e2e28120d38ba6)

- - - - -
c5fd37a3 by Mathieu Parent at 2019-01-17T21:16:15Z
Really ignore nmbd start errors when there is no non-loopback interface (Closes: #893762)

(cherry picked from commit 26c1eca5d29dc3298366e06f0b27af47efff2e73)

- - - - -
c0175cc4 by Mathieu Parent at 2019-01-17T21:16:15Z
Ignore nmbd start errors when there is  no local IPv4 non-loopback interface (Closes: #859526)

(cherry picked from commit 811596b1694df1956a8c7585dbc766a7de12b254)

- - - - -
b94bd4ad by Stefan Metzmacher at 2019-01-17T21:16:15Z
s3:ntlm_auth: fix memory leak in manage_gensec_request()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit e999b798c6484de3cddad988406f97fc4cc7af79)

- - - - -
0f7d9880 by Stefan Metzmacher at 2019-01-18T06:34:48Z
s3:ntlm_auth: fix memory leak in manage_gensec_request() (Closes: #919611)

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit e999b798c6484de3cddad988406f97fc4cc7af79)

- - - - -
faa8dd2a by Mathieu Parent at 2019-01-18T06:39:25Z
Changelog for previous commits

- - - - -


12 changed files:

- debian/changelog
- debian/patches/CVE-2018-14629-v4-5.patch
- + debian/patches/fix-rmdir.patch
- + debian/patches/s3-ntlm_auth-fix-memory-leak-in-manage_gensec_reques.patch
- debian/patches/series
- debian/rules
- debian/samba.postinst
- python/samba/tests/dns.py
- selftest/knownfail.d/dns
- source3/libsmb/cli_smb2_fnum.c
- source3/utils/ntlm_auth.c
- source4/dns_server/dns_query.c


Changes:

=====================================
debian/changelog
=====================================
@@ -1,8 +1,17 @@
 samba (2:4.5.16+dfsg-1) UNRELEASED; urgency=medium
 
-  * New upstream release
-
- -- Mathieu Parent <sathieu at debian.org>  Sat, 29 Dec 2018 22:18:31 +0100
+  * New upstream release (latest 4.5.x)
+    - Drop merged patches
+  * Fix CVE-2018-14629 regression when there're more than 20 records on a non
+    CNAME record.
+  * Fix rmdir on non-empty samba directory (Closes: #915248)
+  * Ignore nmbd start errors when there is no non-loopback interface
+    (Closes: #893762)
+  * Ignore nmbd start errors when there is  no local IPv4 non-loopback interface
+    (Closes: #859526)
+  * s3:ntlm_auth: fix memory leak in manage_gensec_request() (Closes: #919611)
+
+ -- Mathieu Parent <sathieu at debian.org>  Fri, 18 Jan 2019 07:35:15 +0100
 
 samba (2:4.5.12+dfsg-2+deb9u4) stretch-security; urgency=high
 


=====================================
debian/patches/CVE-2018-14629-v4-5.patch
=====================================
@@ -191,3 +191,284 @@ index bef21f6bdaf..51a86198b54 100644
 -- 
 2.11.0
 
+From 6c73a2b3d77115d69f99baa2452d6539c697fc3b Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze at samba.org>
+Date: Wed, 28 Nov 2018 15:21:56 +0100
+Subject: [PATCH 1/2] CVE-2018-14629 dns: fix CNAME loop prevention using
+ counter regression
+
+The loop prevention should only be done for CNAME records!
+
+Otherwise we truncate the answer records for A, AAAA or
+SRV queries, which is a bad idea if you have more than 20 DCs.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13600
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+---
+ source4/dns_server/dns_query.c | 29 ++++++++++++++++++++---------
+ 1 file changed, 20 insertions(+), 9 deletions(-)
+
+diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
+index 0c26f9f8fb5..19c4dc32faa 100644
+--- a/source4/dns_server/dns_query.c
++++ b/source4/dns_server/dns_query.c
+@@ -439,7 +439,8 @@ static struct tevent_req *handle_authoritative_send(
+ 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ 	struct dns_server *dns, const char *forwarder,
+ 	struct dns_name_question *question,
+-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs);
++	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
++	size_t cname_depth);
+ static WERROR handle_authoritative_recv(struct tevent_req *req);
+ 
+ struct handle_dnsrpcrec_state {
+@@ -455,7 +456,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
+ 	struct dns_server *dns, const char *forwarder,
+ 	const struct dns_name_question *question,
+ 	struct dnsp_DnssrvRpcRecord *rec,
+-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
++	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
++	size_t cname_depth)
+ {
+ 	struct tevent_req *req, *subreq;
+ 	struct handle_dnsrpcrec_state *state;
+@@ -471,7 +473,7 @@ static struct tevent_req *handle_dnsrpcrec_send(
+ 	state->answers = answers;
+ 	state->nsrecs = nsrecs;
+ 
+-	if (talloc_array_length(*answers) >= MAX_Q_RECURSION_DEPTH) {
++	if (cname_depth >= MAX_Q_RECURSION_DEPTH) {
+ 		tevent_req_done(req);
+ 		return tevent_req_post(req, ev);
+ 	}
+@@ -516,7 +518,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
+ 	if (dns_authoritative_for_zone(dns, new_q->name)) {
+ 		subreq = handle_authoritative_send(
+ 			state, ev, dns, forwarder, new_q,
+-			state->answers, state->nsrecs);
++			state->answers, state->nsrecs,
++			cname_depth + 1);
+ 		if (tevent_req_nomem(subreq, req)) {
+ 			return tevent_req_post(req, ev);
+ 		}
+@@ -600,6 +603,8 @@ struct handle_authoritative_state {
+ 
+ 	struct dns_res_rec **answers;
+ 	struct dns_res_rec **nsrecs;
++
++	size_t cname_depth;
+ };
+ 
+ static void handle_authoritative_done(struct tevent_req *subreq);
+@@ -608,7 +613,8 @@ static struct tevent_req *handle_authoritative_send(
+ 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ 	struct dns_server *dns, const char *forwarder,
+ 	struct dns_name_question *question,
+-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
++	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
++	size_t cname_depth)
+ {
+ 	struct tevent_req *req, *subreq;
+ 	struct handle_authoritative_state *state;
+@@ -626,6 +632,7 @@ static struct tevent_req *handle_authoritative_send(
+ 	state->forwarder = forwarder;
+ 	state->answers = answers;
+ 	state->nsrecs = nsrecs;
++	state->cname_depth = cname_depth;
+ 
+ 	werr = dns_name2dn(dns, state, question->name, &dn);
+ 	if (tevent_req_werror(req, werr)) {
+@@ -647,7 +654,8 @@ static struct tevent_req *handle_authoritative_send(
+ 	subreq = handle_dnsrpcrec_send(
+ 		state, state->ev, state->dns, state->forwarder,
+ 		state->question, &state->recs[state->recs_done],
+-		state->answers, state->nsrecs);
++		state->answers, state->nsrecs,
++		state->cname_depth);
+ 	if (tevent_req_nomem(subreq, req)) {
+ 		return tevent_req_post(req, ev);
+ 	}
+@@ -679,7 +687,8 @@ static void handle_authoritative_done(struct tevent_req *subreq)
+ 	subreq = handle_dnsrpcrec_send(
+ 		state, state->ev, state->dns, state->forwarder,
+ 		state->question, &state->recs[state->recs_done],
+-		state->answers, state->nsrecs);
++		state->answers, state->nsrecs,
++		state->cname_depth);
+ 	if (tevent_req_nomem(subreq, req)) {
+ 		return;
+ 	}
+@@ -1010,7 +1019,8 @@ struct tevent_req *dns_server_process_query_send(
+ 
+ 		subreq = handle_authoritative_send(
+ 			state, ev, dns, (forwarders == NULL ? NULL : forwarders[0]),
+-			&in->questions[0], &state->answers, &state->nsrecs);
++			&in->questions[0], &state->answers, &state->nsrecs,
++			0); /* cname_depth */
+ 		if (tevent_req_nomem(subreq, req)) {
+ 			return tevent_req_post(req, ev);
+ 		}
+@@ -1112,7 +1122,8 @@ static void dns_server_process_query_got_auth(struct tevent_req *subreq)
+ 		subreq = handle_authoritative_send(state, state->ev, state->dns,
+ 						   state->forwarders->forwarder,
+ 						   state->question, &state->answers,
+-						   &state->nsrecs);
++						   &state->nsrecs,
++						   0); /* cname_depth */
+ 
+ 		if (tevent_req_nomem(subreq, req)) {
+ 			return;
+-- 
+2.19.2
+
+
+From 77fac10d0171b731bce38e5596928b6d618ed4d8 Mon Sep 17 00:00:00 2001
+From: Aaron Haslett <aaronhaslett at catalyst.net.nz>
+Date: Fri, 30 Nov 2018 18:37:27 +1300
+Subject: [PATCH 2/2] CVE-2018-14629: Tests to expose regression from dns cname
+ loop fix
+
+These tests expose the regression described by Stefan Metzmacher in
+discussion on the bugzilla paged linked below.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13600
+Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
+---
+ python/samba/tests/dns.py | 97 +++++++++++++++++++++++++++++++++++++++
+ selftest/knownfail.d/dns  | 14 +++++-
+ 2 files changed, 109 insertions(+), 2 deletions(-)
+
+diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
+index 102269c7156..65e4a3b0b3f 100644
+--- a/python/samba/tests/dns.py
++++ b/python/samba/tests/dns.py
+@@ -918,6 +918,103 @@ class TestComplexQueries(DNSTest):
+         max_recursion_depth = 20
+         self.assertEquals(len(response.answers), max_recursion_depth)
+ 
++    # Make sure cname limit doesn't count other records.  This is a generic
++    # test called in tests below
++    def max_rec_test(self, rtype, rec_gen):
++        name = "limittestrec{0}.{1}".format(rtype, self.get_dns_domain())
++        limit = 20
++        num_recs_to_enter = limit + 5
++
++        for i in range(1, num_recs_to_enter+1):
++            ip = rec_gen(i)
++            self.make_dns_update(name, ip, rtype)
++
++        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
++        questions = []
++
++        q = self.make_name_question(name,
++                                    rtype,
++                                    dns.DNS_QCLASS_IN)
++        questions.append(q)
++        self.finish_name_packet(p, questions)
++
++        response = self.dns_transaction_udp(p, host=self.server_ip)
++
++        self.assertEqual(len(response.answers), num_recs_to_enter)
++
++    def test_record_limit_A(self):
++        def ip4_gen(i):
++            return "127.0.0." + str(i)
++        self.max_rec_test(rtype=dns.DNS_QTYPE_A, rec_gen=ip4_gen)
++
++    def test_record_limit_AAAA(self):
++        def ip6_gen(i):
++            return "AAAA:0:0:0:0:0:0:" + str(i)
++        self.max_rec_test(rtype=dns.DNS_QTYPE_AAAA, rec_gen=ip6_gen)
++
++    def test_record_limit_SRV(self):
++        def srv_gen(i):
++            rec = dns.srv_record()
++            rec.priority = 1
++            rec.weight = 1
++            rec.port = 92
++            rec.target = "srvtestrec" + str(i)
++            return rec
++        self.max_rec_test(rtype=dns.DNS_QTYPE_SRV, rec_gen=srv_gen)
++
++    # Same as test_record_limit_A but with a preceding CNAME follow
++    def test_cname_limit(self):
++        cname1 = "cnamelimittestrec." + self.get_dns_domain()
++        cname2 = "cnamelimittestrec2." + self.get_dns_domain()
++        cname3 = "cnamelimittestrec3." + self.get_dns_domain()
++        ip_prefix = '127.0.0.'
++        limit = 20
++        num_recs_to_enter = limit + 5
++
++        self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME)
++        self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME)
++        num_arecs_to_enter = num_recs_to_enter - 2
++        for i in range(1, num_arecs_to_enter+1):
++            ip = ip_prefix + str(i)
++            self.make_dns_update(cname3, ip, dns.DNS_QTYPE_A)
++
++        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
++        questions = []
++
++        q = self.make_name_question(cname1,
++                                    dns.DNS_QTYPE_A,
++                                    dns.DNS_QCLASS_IN)
++        questions.append(q)
++        self.finish_name_packet(p, questions)
++
++        response = self.dns_transaction_udp(p, host=self.server_ip)
++
++        self.assertEqual(len(response.answers), num_recs_to_enter)
++
++    # ANY query on cname record shouldn't follow the link
++    def test_cname_any_query(self):
++        cname1 = "cnameanytestrec." + self.get_dns_domain()
++        cname2 = "cnameanytestrec2." + self.get_dns_domain()
++        cname3 = "cnameanytestrec3." + self.get_dns_domain()
++
++        self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME)
++        self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME)
++
++        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
++        questions = []
++
++        q = self.make_name_question(cname1,
++                                    dns.DNS_QTYPE_ALL,
++                                    dns.DNS_QCLASS_IN)
++        questions.append(q)
++        self.finish_name_packet(p, questions)
++
++        response = self.dns_transaction_udp(p, host=self.server_ip)
++
++        self.assertEqual(len(response.answers), 1)
++        self.assertEqual(response.answers[0].name, cname1)
++        self.assertEqual(response.answers[0].rdata, cname2)
++
+ 
+ class TestInvalidQueries(DNSTest):
+ 
+diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns
+index 916afc1af85..a9b16eaac2a 100644
+--- a/selftest/knownfail.d/dns
++++ b/selftest/knownfail.d/dns
+@@ -1,5 +1,15 @@
+ #
+-# rodc and vampire_dc require signed dns updates, so the test setup
+-# fails, but the test does run on fl2003dc
++# rodc and vampire_dc require signed dns updates, so these tests' setups
++# fail, but they pass on fl2003dc
+ ^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(rodc:local\)
+ ^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_A\(rodc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_A\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_AAAA\(rodc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_AAAA\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_SRV\(rodc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_SRV\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit\(rodc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(vampire_dc:local\)
++^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(rodc:local\)
+-- 
+2.19.2
+


=====================================
debian/patches/fix-rmdir.patch
=====================================
@@ -0,0 +1,47 @@
+From: Anoop C S <anoopcs at redhat.com>
+Date: Thu, 9 Aug 2018 12:28:41 +0530
+Subject: s3/libsmb: Explicitly set delete_on_close token for rmdir
+
+The current implementation of `rmdir` hopes to get the directory deleted
+on closing last open handle when FILE_DELETE_ON_CLOSE is set on it. But
+for non-empty directories Windows doesn't error out during an open call.
+Following that we internally refuse to set initial delete_on_close while
+opening a non-empty directory. This prevents us from trying to delete
+the directory when last open handle is closed.
+
+Instead of relying on FILE_DELETE_ON_CLOSE during an open we explicitly
+set delete_on_close token on directory handle once it is available. This
+ensures that NT_STATUS_DIRECTORY_NOT_EMPTY is returned for `rmdir` on
+non-empty directories while closing open directory handle.
+
+Applied-Upstream: https://github.com/samba-team/samba/commit/6b68e3eca631c04d6d57c489daf60f64732fc86d
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=13204
+Bug-Debian: https://bugs.debian.org/915248
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/samba/+bug/1795772
+
+diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
+index 237e6bb2b..d4ff8bd28 100644
+--- a/source3/libsmb/cli_smb2_fnum.c
++++ b/source3/libsmb/cli_smb2_fnum.c
+@@ -682,13 +682,20 @@ NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
+ 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
+ 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
+ 			FILE_OPEN,		/* create_disposition */
+-			FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE,	/* create_options */
++			FILE_DIRECTORY_FILE,	/* create_options */
+ 			&fnum,
+ 			NULL);
+ 
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		return status;
+ 	}
++
++	status = cli_smb2_delete_on_close(cli, fnum, true);
++	if (!NT_STATUS_IS_OK(status)) {
++		cli_smb2_close_fnum(cli, fnum);
++		return status;
++	}
++
+ 	return cli_smb2_close_fnum(cli, fnum);
+ }
+ 


=====================================
debian/patches/s3-ntlm_auth-fix-memory-leak-in-manage_gensec_reques.patch
=====================================
@@ -0,0 +1,96 @@
+From 1606ab1baf02c8d3797fdc6f347af2c8552996a0 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze at samba.org>
+Date: Tue, 4 Apr 2017 11:52:56 +0200
+Subject: [PATCH] s3:ntlm_auth: fix memory leak in manage_gensec_request()
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12736
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andreas Schneider <asn at samba.org>
+(cherry picked from commit e999b798c6484de3cddad988406f97fc4cc7af79)
+
+Bug-Debian: https://bugs.debian.org/919611
+---
+ source3/utils/ntlm_auth.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
+index 84269a139a3..d35e8f050b6 100644
+--- a/source3/utils/ntlm_auth.c
++++ b/source3/utils/ntlm_auth.c
+@@ -1290,6 +1290,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 
+ 	TALLOC_CTX *mem_ctx;
+ 
++	mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
++
+ 	if (*private1) {
+ 		state = (struct gensec_ntlm_state *)*private1;
+ 	} else {
+@@ -1307,6 +1309,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 	if (strlen(buf) < 2) {
+ 		DEBUG(1, ("query [%s] invalid", buf));
+ 		x_fprintf(x_stdout, "BH Query invalid\n");
++		talloc_free(mem_ctx);
+ 		return;
+ 	}
+ 
+@@ -1316,9 +1319,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 			talloc_free(want_feature_list);
+ 			want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
+ 			x_fprintf(x_stdout, "OK\n");
++			talloc_free(mem_ctx);
+ 			return;
+ 		}
+-		in = base64_decode_data_blob(buf + 3);
++		in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
+ 	} else {
+ 		in = data_blob(NULL, 0);
+ 	}
+@@ -1331,7 +1335,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 	} else if ( (strncmp(buf, "OK", 2) == 0)) {
+ 		/* Just return BH, like ntlm_auth from Samba 3 does. */
+ 		x_fprintf(x_stdout, "BH Command expected\n");
+-		data_blob_free(&in);
++		talloc_free(mem_ctx);
+ 		return;
+ 	} else if ( (strncmp(buf, "TT ", 3) != 0) &&
+ 		    (strncmp(buf, "KK ", 3) != 0) &&
+@@ -1343,12 +1347,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 		    (strncmp(buf, "GF", 2) != 0)) {
+ 		DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
+ 		x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
+-		data_blob_free(&in);
++		talloc_free(mem_ctx);
+ 		return;
+ 	}
+ 
+-	mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
+-
+ 	/* setup gensec */
+ 	if (!(state->gensec_state)) {
+ 		switch (stdio_helper_mode) {
+@@ -1478,7 +1480,6 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 					     state->set_password,
+ 					     CRED_SPECIFIED);
+ 		x_fprintf(x_stdout, "OK\n");
+-		data_blob_free(&in);
+ 		talloc_free(mem_ctx);
+ 		return;
+ 	}
+@@ -1510,10 +1511,12 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ 		neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
+ 		if (neg_flags == 0) {
+ 			x_fprintf(x_stdout, "BH\n");
++			talloc_free(mem_ctx);
+ 			return;
+ 		}
+ 
+ 		x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
++		talloc_free(mem_ctx);
+ 		return;
+ 	}
+ 
+-- 
+2.19.2
+


=====================================
debian/patches/series
=====================================
@@ -21,3 +21,5 @@ CVE-2018-10858-4.6.patch
 CVE-2018-14629-v4-5.patch
 CVE-2018-16841-master.patch
 CVE-2018-16851-master.patch
+fix-rmdir.patch
+s3-ntlm_auth-fix-memory-leak-in-manage_gensec_reques.patch


=====================================
debian/rules
=====================================
@@ -209,7 +209,7 @@ override_dh_installchangelogs:
 override_dh_installinit:
 ifneq (,$(filter samba, $(shell dh_listpackages)))
 	dh_installinit -psamba --name smbd
-	dh_installinit -psamba --name nmbd
+	dh_installinit -psamba --name nmbd --error-handler nmbd_error_handler
 	dh_installinit -psamba --name samba-ad-dc
 	dh_installinit -psamba --noscripts
 	dh_installinit -psamba --no-start --name reload-smbd


=====================================
debian/samba.postinst
=====================================
@@ -6,6 +6,23 @@
 
 set -e
 
+nmbd_error_handler() {
+    if [ -d /sys/class/net/lo ] && ls /sys/class/net | grep -qv ^lo$; then
+        # https://bugs.debian.org/893762
+        echo 'WARNING: nmbd failed to start as there is no non-loopback interfaces available.'
+        echo 'Either add an interface or set "disable netbios = yes" in smb.conf and run "systemctl mask nmbd"'
+        return 0
+    elif command -v ip > /dev/null && ip a show | grep '^[[:space:]]*inet ' | grep -vq ' lo$'; then
+        # https://bugs.debian.org/859526
+        echo 'WARNING: nmbd failed to start as there is no local IPv4 non-loopback interfaces available.'
+        echo 'Either add an IPv4 address or set "disable netbios = yes" in smb.conf and run "systemctl mask nmbd"'
+        return 0
+    else
+        echo 'ERROR: nmbd failed to start.'
+        return 1 # caught by set -e
+    fi
+}
+
 # We generate several files during the postinst, and we don't want
 #	them to be readable only by root.
 umask 022


=====================================
python/samba/tests/dns.py
=====================================
@@ -918,6 +918,103 @@ class TestComplexQueries(DNSTest):
         max_recursion_depth = 20
         self.assertEquals(len(response.answers), max_recursion_depth)
 
+    # Make sure cname limit doesn't count other records.  This is a generic
+    # test called in tests below
+    def max_rec_test(self, rtype, rec_gen):
+        name = "limittestrec{0}.{1}".format(rtype, self.get_dns_domain())
+        limit = 20
+        num_recs_to_enter = limit + 5
+
+        for i in range(1, num_recs_to_enter+1):
+            ip = rec_gen(i)
+            self.make_dns_update(name, ip, rtype)
+
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        questions = []
+
+        q = self.make_name_question(name,
+                                    rtype,
+                                    dns.DNS_QCLASS_IN)
+        questions.append(q)
+        self.finish_name_packet(p, questions)
+
+        response = self.dns_transaction_udp(p, host=self.server_ip)
+
+        self.assertEqual(len(response.answers), num_recs_to_enter)
+
+    def test_record_limit_A(self):
+        def ip4_gen(i):
+            return "127.0.0." + str(i)
+        self.max_rec_test(rtype=dns.DNS_QTYPE_A, rec_gen=ip4_gen)
+
+    def test_record_limit_AAAA(self):
+        def ip6_gen(i):
+            return "AAAA:0:0:0:0:0:0:" + str(i)
+        self.max_rec_test(rtype=dns.DNS_QTYPE_AAAA, rec_gen=ip6_gen)
+
+    def test_record_limit_SRV(self):
+        def srv_gen(i):
+            rec = dns.srv_record()
+            rec.priority = 1
+            rec.weight = 1
+            rec.port = 92
+            rec.target = "srvtestrec" + str(i)
+            return rec
+        self.max_rec_test(rtype=dns.DNS_QTYPE_SRV, rec_gen=srv_gen)
+
+    # Same as test_record_limit_A but with a preceding CNAME follow
+    def test_cname_limit(self):
+        cname1 = "cnamelimittestrec." + self.get_dns_domain()
+        cname2 = "cnamelimittestrec2." + self.get_dns_domain()
+        cname3 = "cnamelimittestrec3." + self.get_dns_domain()
+        ip_prefix = '127.0.0.'
+        limit = 20
+        num_recs_to_enter = limit + 5
+
+        self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME)
+        self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME)
+        num_arecs_to_enter = num_recs_to_enter - 2
+        for i in range(1, num_arecs_to_enter+1):
+            ip = ip_prefix + str(i)
+            self.make_dns_update(cname3, ip, dns.DNS_QTYPE_A)
+
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        questions = []
+
+        q = self.make_name_question(cname1,
+                                    dns.DNS_QTYPE_A,
+                                    dns.DNS_QCLASS_IN)
+        questions.append(q)
+        self.finish_name_packet(p, questions)
+
+        response = self.dns_transaction_udp(p, host=self.server_ip)
+
+        self.assertEqual(len(response.answers), num_recs_to_enter)
+
+    # ANY query on cname record shouldn't follow the link
+    def test_cname_any_query(self):
+        cname1 = "cnameanytestrec." + self.get_dns_domain()
+        cname2 = "cnameanytestrec2." + self.get_dns_domain()
+        cname3 = "cnameanytestrec3." + self.get_dns_domain()
+
+        self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME)
+        self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME)
+
+        p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
+        questions = []
+
+        q = self.make_name_question(cname1,
+                                    dns.DNS_QTYPE_ALL,
+                                    dns.DNS_QCLASS_IN)
+        questions.append(q)
+        self.finish_name_packet(p, questions)
+
+        response = self.dns_transaction_udp(p, host=self.server_ip)
+
+        self.assertEqual(len(response.answers), 1)
+        self.assertEqual(response.answers[0].name, cname1)
+        self.assertEqual(response.answers[0].rdata, cname2)
+
 
 class TestInvalidQueries(DNSTest):
 


=====================================
selftest/knownfail.d/dns
=====================================
@@ -1,5 +1,15 @@
 #
-# rodc and vampire_dc require signed dns updates, so the test setup
-# fails, but the test does run on fl2003dc
+# rodc and vampire_dc require signed dns updates, so these tests' setups
+# fail, but they pass on fl2003dc
 ^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(rodc:local\)
 ^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_A\(rodc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_A\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_AAAA\(rodc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_AAAA\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_SRV\(rodc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_record_limit_SRV\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_limit\(rodc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(vampire_dc:local\)
+^samba.tests.dns.__main__.TestComplexQueries.test_cname_any_query\(rodc:local\)


=====================================
source3/libsmb/cli_smb2_fnum.c
=====================================
@@ -550,13 +550,20 @@ NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
 			FILE_OPEN,		/* create_disposition */
-			FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE,	/* create_options */
+			FILE_DIRECTORY_FILE,	/* create_options */
 			&fnum,
 			NULL);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
+
+	status = cli_smb2_delete_on_close(cli, fnum, true);
+	if (!NT_STATUS_IS_OK(status)) {
+		cli_smb2_close_fnum(cli, fnum);
+		return status;
+	}
+
 	return cli_smb2_close_fnum(cli, fnum);
 }
 


=====================================
source3/utils/ntlm_auth.c
=====================================
@@ -1290,6 +1290,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 
 	TALLOC_CTX *mem_ctx;
 
+	mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
+
 	if (*private1) {
 		state = (struct gensec_ntlm_state *)*private1;
 	} else {
@@ -1307,6 +1309,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 	if (strlen(buf) < 2) {
 		DEBUG(1, ("query [%s] invalid", buf));
 		x_fprintf(x_stdout, "BH Query invalid\n");
+		talloc_free(mem_ctx);
 		return;
 	}
 
@@ -1316,9 +1319,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 			talloc_free(want_feature_list);
 			want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
 			x_fprintf(x_stdout, "OK\n");
+			talloc_free(mem_ctx);
 			return;
 		}
-		in = base64_decode_data_blob(buf + 3);
+		in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
 	} else {
 		in = data_blob(NULL, 0);
 	}
@@ -1331,7 +1335,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 	} else if ( (strncmp(buf, "OK", 2) == 0)) {
 		/* Just return BH, like ntlm_auth from Samba 3 does. */
 		x_fprintf(x_stdout, "BH Command expected\n");
-		data_blob_free(&in);
+		talloc_free(mem_ctx);
 		return;
 	} else if ( (strncmp(buf, "TT ", 3) != 0) &&
 		    (strncmp(buf, "KK ", 3) != 0) &&
@@ -1343,12 +1347,10 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 		    (strncmp(buf, "GF", 2) != 0)) {
 		DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
 		x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
-		data_blob_free(&in);
+		talloc_free(mem_ctx);
 		return;
 	}
 
-	mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
-
 	/* setup gensec */
 	if (!(state->gensec_state)) {
 		switch (stdio_helper_mode) {
@@ -1478,7 +1480,6 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 					     state->set_password,
 					     CRED_SPECIFIED);
 		x_fprintf(x_stdout, "OK\n");
-		data_blob_free(&in);
 		talloc_free(mem_ctx);
 		return;
 	}
@@ -1510,10 +1511,12 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
 		neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
 		if (neg_flags == 0) {
 			x_fprintf(x_stdout, "BH\n");
+			talloc_free(mem_ctx);
 			return;
 		}
 
 		x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
+		talloc_free(mem_ctx);
 		return;
 	}
 


=====================================
source4/dns_server/dns_query.c
=====================================
@@ -439,7 +439,8 @@ static struct tevent_req *handle_authoritative_send(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	struct dns_server *dns, const char *forwarder,
 	struct dns_name_question *question,
-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs);
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+	size_t cname_depth);
 static WERROR handle_authoritative_recv(struct tevent_req *req);
 
 struct handle_dnsrpcrec_state {
@@ -455,7 +456,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
 	struct dns_server *dns, const char *forwarder,
 	const struct dns_name_question *question,
 	struct dnsp_DnssrvRpcRecord *rec,
-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+	size_t cname_depth)
 {
 	struct tevent_req *req, *subreq;
 	struct handle_dnsrpcrec_state *state;
@@ -471,7 +473,7 @@ static struct tevent_req *handle_dnsrpcrec_send(
 	state->answers = answers;
 	state->nsrecs = nsrecs;
 
-	if (talloc_array_length(*answers) >= MAX_Q_RECURSION_DEPTH) {
+	if (cname_depth >= MAX_Q_RECURSION_DEPTH) {
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	}
@@ -516,7 +518,8 @@ static struct tevent_req *handle_dnsrpcrec_send(
 	if (dns_authoritative_for_zone(dns, new_q->name)) {
 		subreq = handle_authoritative_send(
 			state, ev, dns, forwarder, new_q,
-			state->answers, state->nsrecs);
+			state->answers, state->nsrecs,
+			cname_depth + 1);
 		if (tevent_req_nomem(subreq, req)) {
 			return tevent_req_post(req, ev);
 		}
@@ -600,6 +603,8 @@ struct handle_authoritative_state {
 
 	struct dns_res_rec **answers;
 	struct dns_res_rec **nsrecs;
+
+	size_t cname_depth;
 };
 
 static void handle_authoritative_done(struct tevent_req *subreq);
@@ -608,7 +613,8 @@ static struct tevent_req *handle_authoritative_send(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 	struct dns_server *dns, const char *forwarder,
 	struct dns_name_question *question,
-	struct dns_res_rec **answers, struct dns_res_rec **nsrecs)
+	struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
+	size_t cname_depth)
 {
 	struct tevent_req *req, *subreq;
 	struct handle_authoritative_state *state;
@@ -626,6 +632,7 @@ static struct tevent_req *handle_authoritative_send(
 	state->forwarder = forwarder;
 	state->answers = answers;
 	state->nsrecs = nsrecs;
+	state->cname_depth = cname_depth;
 
 	werr = dns_name2dn(dns, state, question->name, &dn);
 	if (tevent_req_werror(req, werr)) {
@@ -647,7 +654,8 @@ static struct tevent_req *handle_authoritative_send(
 	subreq = handle_dnsrpcrec_send(
 		state, state->ev, state->dns, state->forwarder,
 		state->question, &state->recs[state->recs_done],
-		state->answers, state->nsrecs);
+		state->answers, state->nsrecs,
+		state->cname_depth);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -679,7 +687,8 @@ static void handle_authoritative_done(struct tevent_req *subreq)
 	subreq = handle_dnsrpcrec_send(
 		state, state->ev, state->dns, state->forwarder,
 		state->question, &state->recs[state->recs_done],
-		state->answers, state->nsrecs);
+		state->answers, state->nsrecs,
+		state->cname_depth);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -1010,7 +1019,8 @@ struct tevent_req *dns_server_process_query_send(
 
 		subreq = handle_authoritative_send(
 			state, ev, dns, (forwarders == NULL ? NULL : forwarders[0]),
-			&in->questions[0], &state->answers, &state->nsrecs);
+			&in->questions[0], &state->answers, &state->nsrecs,
+			0); /* cname_depth */
 		if (tevent_req_nomem(subreq, req)) {
 			return tevent_req_post(req, ev);
 		}
@@ -1112,7 +1122,8 @@ static void dns_server_process_query_got_auth(struct tevent_req *subreq)
 		subreq = handle_authoritative_send(state, state->ev, state->dns,
 						   state->forwarders->forwarder,
 						   state->question, &state->answers,
-						   &state->nsrecs);
+						   &state->nsrecs,
+						   0); /* cname_depth */
 
 		if (tevent_req_nomem(subreq, req)) {
 			return;



View it on GitLab: https://salsa.debian.org/samba-team/samba/compare/2dcb0d3216ba74f7e22f4f4b1ec1595f568c8d07...faa8dd2a11501e75fee2aeeae4e943b0b17aa38c

-- 
View it on GitLab: https://salsa.debian.org/samba-team/samba/compare/2dcb0d3216ba74f7e22f4f4b1ec1595f568c8d07...faa8dd2a11501e75fee2aeeae4e943b0b17aa38c
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-samba-maint/attachments/20190118/62d5fb7d/attachment-0001.html>


More information about the Pkg-samba-maint mailing list