[PR PATCH] [Updated] samba-tool domain trust: fix trust compatibility to Windows Server 1709 and FreeIPA

Stefan Metzmacher metze at samba.org
Mon Jul 23 22:04:36 UTC 2018


Hi Alexander,

here's a patchset that passes all tests.
See https://gitlab.com/samba-team/devel/samba/pipelines/26290634

Please review and push:-)

Thanks!
metze

Am 19.07.2018 um 13:35 schrieb Alexander Bokovoy via samba-technical:
> On to, 19 heinä 2018, Stefan Metzmacher wrote:
>> Hi Alexander,
>>
>> I've implemented the autodetection of smb1 and smb2 for our dcerpc
>> client side.
>>
>> Please review patches 1-13 from the attached patchset and push it.
> Thanks, they look good to me but python/samba/auth_log.py failed due to
> unexpected SMB to SMB2 upgrade. Attached patch should fix a test.
> 
> There is also a failure:
> 
> ERROR: Testsuite[samba4.rpc.lsa.secrets on ncacn_np with with -k no --option=gensec:spnego=no --option=clientntlmv2auth=yes(nt4_dc)]
> 
>>
>> Here's the related pending pipeline:
>> https://gitlab.com/samba-team/devel/samba/pipelines/26062213
>>
>>>> Can you split the last patch and demonstrate the the test passes with
>>>> a temporary file in selftest/knownfail.d/ and then gets fixed with the
>>>> changes. From reading the test I guess it won't fail as the bug happens
>>>> in two places.
>>> Thing is, it will not fail for wrong salt too because we are running
>>> against the same code that uses the same method to generate salt
>>> principal. So before the patch we've got 'EXAMPLE.COMFOO$' as a salt,
>>> after the patch we'd get 'EXAMPLE.COMkrbtgtFOO' but in both cases both
>>> client and KDC would be operating with the same salt because we retrieve
>>> this keytab from the same KDC.
>>>
>>> I wonder if we can retrieve it from a different KDC and store under
>>> the proper principal but current code for keytab retrieval in libnet
>>> doesn't handle that because it has no way to specify a different
>>> principal name when writing keys to a keytab (we want to retrieve
>>> FOO$@EXAMPLE.COM as EXAMPLE$@FOO.COM and then try to auth against
>>> FOO.COM KDC).
>>>
>>> With my parallel patches (in works) to FreeIPA and SSSD, I get Samba AD
>>> DC properly trusted by FreeIPA and FreeIPA properly trusted by Samba AD
>>> DC when trust is driven from FreeIPA side. So salt fixes helped, for
>>> cases when TDA is used for authentication by both sides. There
>>> is a remaining need to fix cross-realm TGT on FreeIPA side to allow
>>> FreeIPA -> Samba AD leg to work with cross-realm referral issuance.
>>> Samba AD -> FreeIPA leg works already.
>>
>> I ported the patch to master (some defines are different...)
>>
>> The pipeline with the complete set is:
>> https://gitlab.com/samba-team/devel/samba/pipelines/26062727
>>
>> In the commit message of path 14 I added some TODOs:
>>
>>     TODO: unit tests: loop over all account types with, loop over names with
>>     and without upn, with and without '$'. Use 'eXaMpLe.COM' and similar
>>     names to check the correct upper/lower case result.
>>
>>     TODO: Also verify this against windows...
>>     A test can create objects via ldap and/or lsa (for trusts)
>>     then get the object including supplementalCredentials
>>     via drsuapi (as admin) and check the stored salt.
>>     We should have similar tests already.
>>
>> I think we need at least some test that can't fail because
>> of a symmetric fix.
>>
>> Would you have time to work on such tests?
> Unfortunately not until second half of August. If you have time to do it
> before that, it would be appreciated.
> 

-------------- next part --------------
From 1d7c4f1f38fa4fe6ed96f2c04264185611204f71 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 19 Jul 2018 07:32:08 +0200
Subject: [PATCH 01/16] librpc: add binding handle support for [smb1]

This will be used to force smb1.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 librpc/rpc/binding.c    | 1 +
 librpc/rpc/rpc_common.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c
index 63ba682a577e..aa8cc6b46c6f 100644
--- a/librpc/rpc/binding.c
+++ b/librpc/rpc/binding.c
@@ -103,6 +103,7 @@ static const struct ncacn_option {
 	{"print", DCERPC_DEBUG_PRINT_BOTH},
 	{"padcheck", DCERPC_DEBUG_PAD_CHECK},
 	{"bigendian", DCERPC_PUSH_BIGENDIAN},
+	{"smb1", DCERPC_SMB1},
 	{"smb2", DCERPC_SMB2},
 	{"ndr64", DCERPC_NDR64},
 	{"packet", DCERPC_PACKET},
diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h
index d6b2d5dbc055..cdc9fe8ac882 100644
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -108,6 +108,8 @@ struct dcerpc_binding;
 
 #define DCERPC_PACKET			(1<<26)
 
+#define DCERPC_SMB1                    (1<<27)
+
 /* The following definitions come from ../librpc/rpc/dcerpc_error.c  */
 
 const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
-- 
2.17.1


From a3050ad2c6ebe46a67acf79d2341bd1e3296ce07 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 15:36:31 +0200
Subject: [PATCH 02/16] s4:libcli: split out smb_raw_negotiate_fill_transport()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/rawnegotiate.c | 74 ++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 30 deletions(-)

diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c
index 73c9123411d6..cec081c364a4 100644
--- a/source4/libcli/raw/rawnegotiate.c
+++ b/source4/libcli/raw/rawnegotiate.c
@@ -28,6 +28,47 @@
 #include "../libcli/smb/smbXcli_base.h"
 #include "../lib/util/tevent_ntstatus.h"
 
+NTSTATUS smb_raw_negotiate_fill_transport(struct smbcli_transport *transport)
+{
+	struct smbcli_negotiate *n = &transport->negotiate;
+	struct smbXcli_conn *c = transport->conn;
+	NTTIME ntt;
+
+	n->protocol = smbXcli_conn_protocol(c);
+	if (n->protocol > PROTOCOL_NT1) {
+		return NT_STATUS_REVISION_MISMATCH;
+	}
+
+	n->sec_mode = smb1cli_conn_server_security_mode(c);
+	n->max_mux  = smbXcli_conn_max_requests(c);
+	n->max_xmit = smb1cli_conn_max_xmit(c);
+	n->sesskey  = smb1cli_conn_server_session_key(c);
+	n->capabilities = smb1cli_conn_capabilities(c);;
+
+	/* this time arrives in real GMT */
+	ntt = smbXcli_conn_server_system_time(c);
+	n->server_time = nt_time_to_unix(ntt);
+	n->server_zone = smb1cli_conn_server_time_zone(c);
+
+	if (n->capabilities & CAP_EXTENDED_SECURITY) {
+		const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c);
+		if (b) {
+			n->secblob = *b;
+		}
+	} else {
+		const uint8_t *p = smb1cli_conn_server_challenge(c);
+		if (p) {
+			n->secblob = data_blob_const(p, 8);
+		}
+	}
+
+	n->readbraw_supported = smb1cli_conn_server_readbraw(c);
+	n->readbraw_supported = smb1cli_conn_server_writebraw(c);
+	n->lockread_supported = smb1cli_conn_server_lockread(c);
+
+	return NT_STATUS_OK;
+}
+
 struct smb_raw_negotiate_state {
 	struct smbcli_transport *transport;
 };
@@ -82,10 +123,7 @@ static void smb_raw_negotiate_done(struct tevent_req *subreq)
 	struct smb_raw_negotiate_state *state =
 		tevent_req_data(req,
 		struct smb_raw_negotiate_state);
-	struct smbcli_negotiate *n = &state->transport->negotiate;
-	struct smbXcli_conn *c = state->transport->conn;
 	NTSTATUS status;
-	NTTIME ntt;
 
 	status = smbXcli_negprot_recv(subreq);
 	TALLOC_FREE(subreq);
@@ -93,35 +131,11 @@ static void smb_raw_negotiate_done(struct tevent_req *subreq)
 		return;
 	}
 
-	n->protocol = smbXcli_conn_protocol(c);
-
-	n->sec_mode = smb1cli_conn_server_security_mode(c);
-	n->max_mux  = smbXcli_conn_max_requests(c);
-	n->max_xmit = smb1cli_conn_max_xmit(c);
-	n->sesskey  = smb1cli_conn_server_session_key(c);
-	n->capabilities = smb1cli_conn_capabilities(c);;
-
-	/* this time arrives in real GMT */
-	ntt = smbXcli_conn_server_system_time(c);
-	n->server_time = nt_time_to_unix(ntt);
-	n->server_zone = smb1cli_conn_server_time_zone(c);
-
-	if (n->capabilities & CAP_EXTENDED_SECURITY) {
-		const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c);
-		if (b) {
-			n->secblob = *b;
-		}
-	} else {
-		const uint8_t *p = smb1cli_conn_server_challenge(c);
-		if (p) {
-			n->secblob = data_blob_const(p, 8);
-		}
+	status = smb_raw_negotiate_fill_transport(state->transport);
+	if (tevent_req_nterror(req, status)) {
+		return;
 	}
 
-	n->readbraw_supported = smb1cli_conn_server_readbraw(c);
-	n->readbraw_supported = smb1cli_conn_server_writebraw(c);
-	n->lockread_supported = smb1cli_conn_server_lockread(c);
-
 	tevent_req_done(req);
 }
 
-- 
2.17.1


From e69abf9e9a2a81890dd73e9454476fa65fa458e6 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 15:36:52 +0200
Subject: [PATCH 03/16] s4:libcli: add smbcli_transport_raw_init()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/clitransport.c | 44 +++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c
index d0dd1f9dee6a..47b8dbf3ae7f 100644
--- a/source4/libcli/raw/clitransport.c
+++ b/source4/libcli/raw/clitransport.c
@@ -113,6 +113,50 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock,
 	return transport;
 }
 
+/*
+  create a transport structure based on an established socket
+*/
+NTSTATUS smbcli_transport_raw_init(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   struct smbXcli_conn **_conn,
+				   const struct smbcli_options *options,
+				   struct smbcli_transport **_transport)
+{
+	struct smbcli_transport *transport = NULL;
+	NTSTATUS status;
+
+	if (*_conn == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	transport = talloc_zero(mem_ctx, struct smbcli_transport);
+	if (transport == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	transport->ev = ev;
+	transport->options = *options;
+
+	/*
+	 * First only set the pointer without move.
+	 */
+	transport->conn = *_conn;
+	status = smb_raw_negotiate_fill_transport(transport);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(transport);
+		return status;
+	}
+
+	talloc_set_destructor(transport, transport_destructor);
+
+	/*
+	 * Now move it away from the caller...
+	 */
+	transport->conn = talloc_move(transport, _conn);
+	*_transport = transport;
+	return NT_STATUS_OK;
+}
+
 /*
   mark the transport as dead
 */
-- 
2.17.1


From dcfa5fd44c84dc5173e902b58baf60bcb75d24d7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 15:01:50 +0200
Subject: [PATCH 04/16] s4:libcli: use talloc_zero() for struct
 smb_composite_connect in fetchfile.c

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb_composite/fetchfile.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/libcli/smb_composite/fetchfile.c b/source4/libcli/smb_composite/fetchfile.c
index d19c86a8d05b..dc6f71b452e2 100644
--- a/source4/libcli/smb_composite/fetchfile.c
+++ b/source4/libcli/smb_composite/fetchfile.c
@@ -131,7 +131,7 @@ struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetc
 	state = talloc(c, struct fetchfile_state);
 	if (state == NULL) goto failed;
 
-	state->connect = talloc(state, struct smb_composite_connect);
+	state->connect = talloc_zero(state, struct smb_composite_connect);
 	if (state->connect == NULL) goto failed;
 
 	state->io = io;
-- 
2.17.1


From 336c65cae5236b3d2eb9bf4bb0e34d9e5793d88c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 15:34:55 +0200
Subject: [PATCH 05/16] s4:libcli: allow passing an already negotiated
 connection to smb_composite_connect()

It will just do the session setup and tree connect steps.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/clitree.c                 |  1 +
 source4/libcli/smb_composite/connect.c       | 48 ++++++++++++++++----
 source4/libcli/smb_composite/smb_composite.h |  1 +
 source4/ntvfs/cifs/vfs_cifs.c                |  1 +
 4 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c
index 11be5485f261..b1b6159e7508 100644
--- a/source4/libcli/raw/clitree.c
+++ b/source4/libcli/raw/clitree.c
@@ -207,6 +207,7 @@ NTSTATUS smbcli_tree_full_connection(TALLOC_CTX *parent_ctx,
 	io.in.called_name = strupper_talloc(tmp_ctx, dest_host);
 	io.in.service = service;
 	io.in.service_type = service_type;
+	io.in.existing_conn = NULL;
 	io.in.credentials = credentials;
 	io.in.gensec_settings = gensec_settings;
 	io.in.fallback_to_anonymous = false;
diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c
index fffa768ac977..582d43ef1730 100644
--- a/source4/libcli/smb_composite/connect.c
+++ b/source4/libcli/smb_composite/connect.c
@@ -228,18 +228,10 @@ static NTSTATUS connect_session_setup(struct composite_context *c,
 	return NT_STATUS_OK;
 }
 
-/*
-  a negprot request has completed
-*/
-static NTSTATUS connect_negprot(struct composite_context *c, 
-				struct smb_composite_connect *io)
+static NTSTATUS connect_send_session(struct composite_context *c,
+				     struct smb_composite_connect *io)
 {
 	struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
-	NTSTATUS status;
-
-	status = smb_raw_negotiate_recv(state->subreq);
-	TALLOC_FREE(state->subreq);
-	NT_STATUS_NOT_OK_RETURN(status);
 
 	/* next step is a session setup */
 	state->session = smbcli_session_init(state->transport, state, true, io->in.session_options);
@@ -281,6 +273,22 @@ static NTSTATUS connect_negprot(struct composite_context *c,
 	return NT_STATUS_OK;
 }
 
+/*
+  a negprot request has completed
+*/
+static NTSTATUS connect_negprot(struct composite_context *c,
+				struct smb_composite_connect *io)
+{
+	struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
+	NTSTATUS status;
+
+	status = smb_raw_negotiate_recv(state->subreq);
+	TALLOC_FREE(state->subreq);
+	NT_STATUS_NOT_OK_RETURN(status);
+
+	return connect_send_session(c, io);
+}
+
 /*
   setup a negprot send 
 */
@@ -432,6 +440,26 @@ struct composite_context *smb_composite_connect_send(struct smb_composite_connec
 	nbt_choose_called_name(state, &state->called,
 			       io->in.called_name, NBT_NAME_SERVER);
 
+	if (io->in.existing_conn != NULL) {
+		NTSTATUS status;
+
+		status = smbcli_transport_raw_init(state,
+						   c->event_ctx,
+						   &io->in.existing_conn,
+						   &io->in.options,
+						   &state->transport);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto failed;
+		}
+
+		status = connect_send_session(c, io);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto failed;
+		}
+
+		return c;
+	}
+
 	state->creq = smbcli_sock_connect_send(state, 
 					       NULL,
 					       io->in.dest_ports,
diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h
index a92c9612c6ac..383946f1307a 100644
--- a/source4/libcli/smb_composite/smb_composite.h
+++ b/source4/libcli/smb_composite/smb_composite.h
@@ -118,6 +118,7 @@ struct smb_composite_connect {
 		const char *called_name;
 		const char *service;
 		const char *service_type;
+		struct smbXcli_conn *existing_conn; /* optional */
 		struct cli_credentials *credentials;
 		bool fallback_to_anonymous;
 		const char *workgroup;
diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c
index 478428e32465..d88c034c6f2a 100644
--- a/source4/ntvfs/cifs/vfs_cifs.c
+++ b/source4/ntvfs/cifs/vfs_cifs.c
@@ -296,6 +296,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
 	io.in.dest_ports = lpcfg_smb_ports(ntvfs->ctx->lp_ctx);
 	io.in.socket_options = lpcfg_socket_options(ntvfs->ctx->lp_ctx);
 	io.in.called_name = host;
+	io.in.existing_conn = NULL;
 	io.in.credentials = credentials;
 	io.in.fallback_to_anonymous = false;
 	io.in.workgroup = lpcfg_workgroup(ntvfs->ctx->lp_ctx);
-- 
2.17.1


From 8b808f57d73007f236b817de0608b74421e80dd8 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 16:43:04 +0200
Subject: [PATCH 06/16] s4:libcli: add smb2_transport_raw_init()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/transport.c | 35 +++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index 166f34b82569..1d08289341ba 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -85,6 +85,41 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
 	return transport;
 }
 
+/*
+  create a transport structure based on an established socket
+*/
+NTSTATUS smb2_transport_raw_init(TALLOC_CTX *mem_ctx,
+				 struct tevent_context *ev,
+				 struct smbXcli_conn **_conn,
+				 const struct smbcli_options *options,
+				 struct smb2_transport **_transport)
+{
+	struct smb2_transport *transport = NULL;
+	enum protocol_types protocol;
+
+	if (*_conn == NULL) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	protocol = smbXcli_conn_protocol(*_conn);
+	if (protocol < PROTOCOL_SMB2_02) {
+		return NT_STATUS_REVISION_MISMATCH;
+	}
+
+	transport = talloc_zero(mem_ctx, struct smb2_transport);
+	if (transport == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	transport->ev = ev;
+	transport->options = *options;
+	transport->conn = talloc_move(transport, _conn);
+
+	talloc_set_destructor(transport, transport_destructor);
+	*_transport = transport;
+	return NT_STATUS_OK;
+}
+
 /*
   mark the transport as dead
 */
-- 
2.17.1


From 94dc4448ebd2027473063aebeffb4c99c31fb92d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 16:43:32 +0200
Subject: [PATCH 07/16] s4:libcli: split out smb2_connect_session_start()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/connect.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c
index 8ff56c9ca8f8..ac37eae6aa89 100644
--- a/source4/libcli/smb2/connect.c
+++ b/source4/libcli/smb2/connect.c
@@ -50,6 +50,7 @@ struct smb2_connect_state {
 	struct smb2_tree *tree;
 };
 
+static void smb2_connect_session_start(struct tevent_req *req);
 static void smb2_connect_socket_done(struct composite_context *creq);
 
 /*
@@ -170,10 +171,6 @@ static void smb2_connect_negprot_done(struct tevent_req *subreq)
 	struct tevent_req *req =
 		tevent_req_callback_data(subreq,
 		struct tevent_req);
-	struct smb2_connect_state *state =
-		tevent_req_data(req,
-		struct smb2_connect_state);
-	struct smb2_transport *transport = state->transport;
 	NTSTATUS status;
 
 	status = smbXcli_negprot_recv(subreq);
@@ -182,6 +179,17 @@ static void smb2_connect_negprot_done(struct tevent_req *subreq)
 		return;
 	}
 
+	smb2_connect_session_start(req);
+}
+
+static void smb2_connect_session_start(struct tevent_req *req)
+{
+	struct smb2_connect_state *state =
+		tevent_req_data(req,
+		struct smb2_connect_state);
+	struct smb2_transport *transport = state->transport;
+	struct tevent_req *subreq = NULL;
+
 	state->session = smb2_session_init(transport, state->gensec_settings, state);
 	if (tevent_req_nomem(state->session, req)) {
 		return;
-- 
2.17.1


From 1e7d58a58ae9a0d193d17366df6b689c2cd5f56b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 16:44:16 +0200
Subject: [PATCH 08/16] s4:libcli: allow passing an already negotiated
 connection to smb2_connect_send()

It will just do the session setup and tree connect steps.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/connect.c       | 21 +++++++++++++++++++++
 source4/librpc/rpc/dcerpc_connect.c |  1 +
 2 files changed, 22 insertions(+)

diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c
index ac37eae6aa89..2dee50218694 100644
--- a/source4/libcli/smb2/connect.c
+++ b/source4/libcli/smb2/connect.c
@@ -64,6 +64,7 @@ struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
 				     const char *share,
 				     struct resolve_context *resolve_ctx,
 				     struct cli_credentials *credentials,
+				     struct smbXcli_conn **existing_conn,
 				     uint64_t previous_session_id,
 				     const struct smbcli_options *options,
 				     const char *socket_options,
@@ -107,6 +108,25 @@ struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	if (existing_conn != NULL) {
+		NTSTATUS status;
+
+		status = smb2_transport_raw_init(state, ev,
+						 existing_conn,
+						 options,
+						 &state->transport);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
+
+		smb2_connect_session_start(req);
+		if (!tevent_req_is_in_progress(req)) {
+			return tevent_req_post(req, ev);
+		}
+
+		return req;
+	}
+
 	creq = smbcli_sock_connect_send(state, NULL, state->ports,
 					state->host, state->resolve_ctx,
 					state->ev, state->socket_options,
@@ -311,6 +331,7 @@ NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
 				   share,
 				   resolve_ctx,
 				   credentials,
+				   NULL, /* existing_conn */
 				   previous_session_id,
 				   options,
 				   socket_options,
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 1252e74b5a9d..a3f25efc0b47 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -301,6 +301,7 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
 			"IPC$",
 			s->io.resolve_ctx,
 			s->io.creds,
+			NULL, /* existing_conn */
 			0, /* previous_session_id */
 			&options,
 			lpcfg_socket_options(lp_ctx),
-- 
2.17.1


From 285d073dbaf28eead0c5b1dc318cc0a11f6b39c3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 23:52:30 +0200
Subject: [PATCH 09/16] s4:libcli: add fallback_to_anonymous to
 smb2_connect_send()

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/connect.c       | 32 +++++++++++++++++++++++++++++
 source4/librpc/rpc/dcerpc_connect.c |  1 +
 2 files changed, 33 insertions(+)

diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c
index 2dee50218694..e4cbf8c5c419 100644
--- a/source4/libcli/smb2/connect.c
+++ b/source4/libcli/smb2/connect.c
@@ -35,6 +35,7 @@
 struct smb2_connect_state {
 	struct tevent_context *ev;
 	struct cli_credentials *credentials;
+	bool fallback_to_anonymous;
 	uint64_t previous_session_id;
 	struct resolve_context *resolve_ctx;
 	const char *host;
@@ -64,6 +65,7 @@ struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
 				     const char *share,
 				     struct resolve_context *resolve_ctx,
 				     struct cli_credentials *credentials,
+				     bool fallback_to_anonymous,
 				     struct smbXcli_conn **existing_conn,
 				     uint64_t previous_session_id,
 				     const struct smbcli_options *options,
@@ -83,6 +85,7 @@ struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
 
 	state->ev = ev;
 	state->credentials = credentials;
+	state->fallback_to_anonymous = fallback_to_anonymous;
 	state->previous_session_id = previous_session_id;
 	state->options = *options;
 	state->host = host;
@@ -240,6 +243,34 @@ static void smb2_connect_session_done(struct tevent_req *subreq)
 
 	status = smb2_session_setup_spnego_recv(subreq);
 	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status) &&
+	    !cli_credentials_is_anonymous(state->credentials) &&
+	    state->fallback_to_anonymous) {
+		struct cli_credentials *anon_creds = NULL;
+
+		/*
+		 * The transport was moved to session,
+		 * we need to revert that before removing
+		 * the old broken session.
+		 */
+		state->transport = talloc_move(state, &state->session->transport);
+		TALLOC_FREE(state->session);
+
+		anon_creds = cli_credentials_init_anon(state);
+		if (tevent_req_nomem(anon_creds, req)) {
+			return;
+		}
+		cli_credentials_set_workstation(anon_creds,
+		   cli_credentials_get_workstation(state->credentials),
+		   CRED_SPECIFIED);
+
+		/*
+		 * retry with anonymous credentials
+		 */
+		state->credentials = anon_creds;
+		smb2_connect_session_start(req);
+		return;
+	}
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
@@ -331,6 +362,7 @@ NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
 				   share,
 				   resolve_ctx,
 				   credentials,
+				   false, /* fallback_to_anonymous */
 				   NULL, /* existing_conn */
 				   previous_session_id,
 				   options,
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index a3f25efc0b47..d31bbe152e3e 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -301,6 +301,7 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
 			"IPC$",
 			s->io.resolve_ctx,
 			s->io.creds,
+			false, /* fallback_to_anonymous */
 			NULL, /* existing_conn */
 			0, /* previous_session_id */
 			&options,
-- 
2.17.1


From a6724b488f94543c72bd61c6f0fa07ea7950886c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 19 Jul 2018 23:04:33 +0200
Subject: [PATCH 10/16] s4:libcli: allow a fallback to NTLMSSP if SPNEGO is not
 supported locally

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/session.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index b2cb8384f959..e94512d3d337 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -195,13 +195,38 @@ struct tevent_req *smb2_session_setup_spnego_send(
 
 	if (state->out_secblob.length > 0) {
 		chosen_oid = GENSEC_OID_SPNEGO;
+		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
+				  gensec_get_name_by_oid(session->gensec,
+							 chosen_oid),
+				  nt_errstr(status)));
+			state->out_secblob = data_blob_null;
+			chosen_oid = GENSEC_OID_NTLMSSP;
+			status = gensec_start_mech_by_oid(session->gensec,
+							  chosen_oid);
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
+					  gensec_get_name_by_oid(session->gensec,
+								 chosen_oid),
+					  nt_errstr(status)));
+			}
+		}
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
 	} else {
 		chosen_oid = GENSEC_OID_NTLMSSP;
-	}
-
-	status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
-	if (tevent_req_nterror(req, status)) {
-		return tevent_req_post(req, ev);
+		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
+				  gensec_get_name_by_oid(session->gensec,
+							 chosen_oid),
+				  nt_errstr(status)));
+		}
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
 	}
 
 	smb2_session_setup_spnego_gensec_next(req);
-- 
2.17.1


From 7952f64d93641760fc3fbf1a8057a3fee3bdb461 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 14:52:43 +0200
Subject: [PATCH 11/16] s4:libcli: add smb_connect_nego_{send,recv}()

This can be used to create a connection up to a negotiated
smbXcli_conn.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb_composite/connect_nego.c  | 209 +++++++++++++++++++
 source4/libcli/smb_composite/smb_composite.h |  22 ++
 source4/libcli/wscript_build                 |  20 +-
 3 files changed, 246 insertions(+), 5 deletions(-)
 create mode 100644 source4/libcli/smb_composite/connect_nego.c

diff --git a/source4/libcli/smb_composite/connect_nego.c b/source4/libcli/smb_composite/connect_nego.c
new file mode 100644
index 000000000000..39fef7f8f274
--- /dev/null
+++ b/source4/libcli/smb_composite/connect_nego.c
@@ -0,0 +1,209 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/composite/composite.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "libcli/smb/smbXcli_base.h"
+
+struct smb_connect_nego_state {
+	struct tevent_context *ev;
+	struct resolve_context *resolve_ctx;
+	const char *socket_options;
+	struct smbcli_options options;
+	const char *dest_hostname;
+	const char *dest_address;
+	const char **dest_ports;
+	const char *target_hostname;
+	struct nbt_name calling, called;
+	struct smbXcli_conn *conn;
+};
+
+static void smb_connect_nego_connect_done(struct composite_context *creq);
+static void smb_connect_nego_nego_done(struct tevent_req *subreq);
+
+struct tevent_req *smb_connect_nego_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct resolve_context *resolve_ctx,
+					 const struct smbcli_options *options,
+					 const char *socket_options,
+					 const char *dest_hostname,
+					 const char *dest_address, /* optional */
+					 const char **dest_ports,
+					 const char *target_hostname,
+					 const char *called_name,
+					 const char *calling_name)
+{
+	struct tevent_req *req = NULL;
+	struct smb_connect_nego_state *state = NULL;
+	struct composite_context *creq = NULL;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct smb_connect_nego_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->resolve_ctx= resolve_ctx;
+	state->options = *options;
+	state->socket_options = socket_options;
+	state->dest_hostname = dest_hostname;
+	state->dest_address = dest_address;
+	state->dest_ports = dest_ports;
+	state->target_hostname = target_hostname;
+
+	make_nbt_name_client(&state->calling, calling_name);
+
+	nbt_choose_called_name(state, &state->called,
+			       called_name, NBT_NAME_SERVER);
+	if (tevent_req_nomem(state->called.name, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	creq = smbcli_sock_connect_send(state,
+					state->dest_address,
+					state->dest_ports,
+					state->dest_hostname,
+					state->resolve_ctx,
+					state->ev,
+					state->socket_options,
+					&state->calling,
+					&state->called);
+	if (tevent_req_nomem(creq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	creq->async.private_data = req;
+	creq->async.fn = smb_connect_nego_connect_done;
+
+	return req;
+}
+
+static void smb_connect_nego_connect_done(struct composite_context *creq)
+{
+	struct tevent_req *req =
+		talloc_get_type_abort(creq->async.private_data,
+		struct tevent_req);
+	struct smb_connect_nego_state *state =
+		tevent_req_data(req,
+		struct smb_connect_nego_state);
+	struct tevent_req *subreq = NULL;
+	struct smbcli_socket *sock = NULL;
+	uint32_t smb1_capabilities;
+	uint32_t timeout_msec = state->options.request_timeout * 1000;
+	NTSTATUS status;
+
+	status = smbcli_sock_connect_recv(creq, state, &sock);
+	creq = NULL;
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	TALLOC_FREE(sock->event.fde);
+	TALLOC_FREE(sock->event.te);
+
+	smb1_capabilities = 0;
+	smb1_capabilities |= CAP_LARGE_FILES;
+	smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
+	smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
+	smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
+	smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
+	smb1_capabilities |= CAP_LWIO;
+
+	if (state->options.ntstatus_support) {
+		smb1_capabilities |= CAP_STATUS32;
+	}
+
+	if (state->options.unicode) {
+		smb1_capabilities |= CAP_UNICODE;
+	}
+
+	if (state->options.use_spnego) {
+		smb1_capabilities |= CAP_EXTENDED_SECURITY;
+	}
+
+	if (state->options.use_level2_oplocks) {
+		smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
+	}
+
+	state->conn = smbXcli_conn_create(state,
+					  sock->sock->fd,
+					  state->target_hostname,
+					  state->options.signing,
+					  smb1_capabilities,
+					  &state->options.client_guid,
+					  state->options.smb2_capabilities);
+	if (tevent_req_nomem(state->conn, req)) {
+		return;
+	}
+	sock->sock->fd = -1;
+	TALLOC_FREE(sock);
+
+	subreq = smbXcli_negprot_send(state,
+				      state->ev,
+				      state->conn,
+				      timeout_msec,
+				      state->options.min_protocol,
+				      state->options.max_protocol,
+				      state->options.max_credits);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, smb_connect_nego_nego_done, req);
+}
+
+static void smb_connect_nego_nego_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	NTSTATUS status;
+
+	status = smbXcli_negprot_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+NTSTATUS smb_connect_nego_recv(struct tevent_req *req,
+			       TALLOC_CTX *mem_ctx,
+			       struct smbXcli_conn **_conn)
+{
+	struct smb_connect_nego_state *state =
+		tevent_req_data(req,
+		struct smb_connect_nego_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
+		return status;
+	}
+
+	*_conn = talloc_move(mem_ctx, &state->conn);
+	tevent_req_received(req);
+	return NT_STATUS_OK;
+}
diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h
index 383946f1307a..e43cbb9dff92 100644
--- a/source4/libcli/smb_composite/smb_composite.h
+++ b/source4/libcli/smb_composite/smb_composite.h
@@ -101,6 +101,28 @@ NTSTATUS smb_composite_savefile_recv(struct composite_context *c);
 NTSTATUS smb_composite_savefile(struct smbcli_tree *tree, 
 				struct smb_composite_savefile *io);
 
+/*
+  a composite request for a low level connection to a remote server. Includes
+
+    - socket establishment
+    - session request
+    - negprot
+*/
+struct tevent_req *smb_connect_nego_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct resolve_context *resolve_ctx,
+					 const struct smbcli_options *options,
+					 const char *socket_options,
+					 const char *dest_hostname,
+					 const char *dest_address, /* optional */
+					 const char **dest_ports,
+					 const char *target_hostname,
+					 const char *called_name,
+					 const char *calling_name);
+NTSTATUS smb_connect_nego_recv(struct tevent_req *req,
+			       TALLOC_CTX *mem_ctx,
+			       struct smbXcli_conn **_conn);
+
 /*
   a composite request for a full connection to a remote server. Includes
 
diff --git a/source4/libcli/wscript_build b/source4/libcli/wscript_build
index 220b028cb368..d3641f538af3 100644
--- a/source4/libcli/wscript_build
+++ b/source4/libcli/wscript_build
@@ -25,11 +25,21 @@ bld.SAMBA_SUBSYSTEM('cli_composite',
 
 
 bld.SAMBA_SUBSYSTEM('LIBCLI_SMB_COMPOSITE',
-	source='smb_composite/loadfile.c smb_composite/savefile.c smb_composite/connect.c smb_composite/sesssetup.c smb_composite/fetchfile.c smb_composite/appendacl.c smb_composite/fsinfo.c smb_composite/smb2.c',
-	deps='LIBCLI_SMB2 tevent-util',
-	public_deps='cli_composite samba-credentials gensec LIBCLI_RESOLVE tevent',
-	private_headers='smb_composite/smb_composite.h',
-	)
+    source='''
+       smb_composite/loadfile.c
+       smb_composite/savefile.c
+       smb_composite/connect_nego.c
+       smb_composite/connect.c
+       smb_composite/sesssetup.c
+       smb_composite/fetchfile.c
+       smb_composite/appendacl.c
+       smb_composite/fsinfo.c
+       smb_composite/smb2.c
+    ''',
+    deps='LIBCLI_SMB2 tevent-util',
+    public_deps='cli_composite samba-credentials gensec LIBCLI_RESOLVE tevent',
+    private_headers='smb_composite/smb_composite.h',
+    )
 
 
 for env in bld.gen_python_environments():
-- 
2.17.1


From d745e059084a74fd7dae7777937d8cff52a88e91 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Thu, 19 Jul 2018 14:07:39 +0300
Subject: [PATCH 12/16] tests/auth_log: Permit SMB2 service description if
 empty binding is used for kerberos authentication

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

Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>

Signed-off-by: Alexander Bokovoy <ab at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/tests/auth_log.py | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/python/samba/tests/auth_log.py b/python/samba/tests/auth_log.py
index cb524d0ed81c..4704b925de58 100644
--- a/python/samba/tests/auth_log.py
+++ b/python/samba/tests/auth_log.py
@@ -28,6 +28,7 @@ from samba.credentials import DONT_USE_KERBEROS, MUST_USE_KERBEROS
 from samba import NTSTATUSError
 from subprocess import call
 from ldb import LdbError
+import re
 
 
 class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
@@ -65,6 +66,20 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
         messages = self.waitForMessages(isLastExpectedMessage, x)
         checkFunction(messages, authTypes, service, binding, protection)
 
+    def _assert_ncacn_np_serviceDescription(self, binding, serviceDescription):
+        # Turn "[foo,bar]" into a list ("foo", "bar") to test
+        # lambda x: x removes anything that evaluates to False,
+        # including empty strings, so we handle "" as well
+        binding_list = filter(lambda x: x, re.compile('[\[,\]]').split(binding))
+
+        # Handle explicit smb2, smb1 or auto negotiation
+        if "smb2" in binding_list:
+            self.assertEquals(serviceDescription, "SMB2")
+        elif "smb1" in binding_list:
+            self.assertEquals(serviceDescription, "SMB")
+        else:
+            self.assertIn(serviceDescription, ["SMB", "SMB2"])
+
     def rpc_ncacn_np_ntlm_check(self, messages, authTypes, service,
                                 binding, protection):
 
@@ -77,7 +92,7 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
         msg = messages[0]
         self.assertEquals("Authentication", msg["type"])
         self.assertEquals("NT_STATUS_OK", msg["Authentication"]["status"])
-        self.assertEquals("SMB",
+        self._assert_ncacn_np_serviceDescription(binding,
                           msg["Authentication"]["serviceDescription"])
         self.assertEquals(authTypes[1],
                           msg["Authentication"]["authDescription"])
@@ -85,7 +100,7 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
         # Check the second message it should be an Authorization
         msg = messages[1]
         self.assertEquals("Authorization", msg["type"])
-        self.assertEquals("SMB",
+        self._assert_ncacn_np_serviceDescription(binding,
                           msg["Authorization"]["serviceDescription"])
         self.assertEquals(authTypes[2], msg["Authorization"]["authType"])
         self.assertEquals("SMB", msg["Authorization"]["transportProtection"])
@@ -145,12 +160,7 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
         # Check the third message it should be an Authorization
         msg = messages[2]
         self.assertEquals("Authorization", msg["type"])
-        serviceDescription = "SMB"
-        print("binding %s" % binding)
-        if binding == "[smb2]":
-            serviceDescription = "SMB2"
-
-        self.assertEquals(serviceDescription,
+        self._assert_ncacn_np_serviceDescription(binding,
                           msg["Authorization"]["serviceDescription"])
         self.assertEquals(authTypes[3], msg["Authorization"]["authType"])
         self.assertEquals("SMB", msg["Authorization"]["transportProtection"])
-- 
2.17.1


From b226e810c935944213b9a1860ce50259639998c3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 23 Jul 2018 00:17:35 +0200
Subject: [PATCH 13/16] python/tests: use explicit "client ipc max protocol =
 NT1" for samba.tests.net_join_no_spnego

The tests rely on SMB1.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/tests/net_join_no_spnego.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/python/samba/tests/net_join_no_spnego.py b/python/samba/tests/net_join_no_spnego.py
index 85c6f888d441..e4dd078f2f65 100644
--- a/python/samba/tests/net_join_no_spnego.py
+++ b/python/samba/tests/net_join_no_spnego.py
@@ -42,6 +42,7 @@ class NetJoinNoSpnegoTests(samba.tests.TestCaseInTempDir):
         super(NetJoinNoSpnegoTests, self).tearDown()
 
     def test_net_join_no_spnego(self):
+        self.lp.set("client ipc max protocol", "NT1")
         self.lp.set("client use spnego", "no")
         netbios_name = "NetJoinNoSpnego"
         machinepass  = "abcdefghij"
@@ -65,6 +66,7 @@ class NetJoinNoSpnegoTests(samba.tests.TestCaseInTempDir):
         self.fail("Shoud have rejected NTLMv2 without SPNEGO")
 
     def test_net_join_no_spnego_ntlmv1(self):
+        self.lp.set("client ipc max protocol", "NT1")
         self.lp.set("client use spnego", "no")
         self.lp.set("client ntlmv2 auth", "no")
         netbios_name = "NetJoinNoSpnego"
-- 
2.17.1


From bb5c2e380a698a0fdd52fcdcbd51a529ab33308e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 18 Jul 2018 16:55:33 +0200
Subject: [PATCH 14/16] s4:librpc: autonegotiate SMB1/2/3

Windows Server 1709 defaults to SMB2 and does not have SMB1 enabled.
When establishing trust, samba-tool does not specify SMB protocol
version and fail by default.

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/librpc/rpc/dcerpc_connect.c | 259 +++++++++++++---------------
 1 file changed, 120 insertions(+), 139 deletions(-)

diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index d31bbe152e3e..c23e85e7cb19 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -36,6 +36,7 @@
 #include "param/param.h"
 #include "libcli/resolve/resolve.h"
 #include "lib/http/http.h"
+#include "lib/util/util_net.h"
 
 struct dcerpc_pipe_connect {
 	struct dcecli_connection *conn;
@@ -76,6 +77,8 @@ static void continue_pipe_open_smb(struct composite_context *ctx)
 }
 
 static void continue_smb_open(struct composite_context *c);
+static void continue_smb2_connect(struct tevent_req *subreq);
+static void continue_smbXcli_connect(struct tevent_req *subreq);
 
 /*
   Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
@@ -132,9 +135,12 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT
 {
 	struct composite_context *c;
 	struct pipe_np_smb_state *s;
-	struct composite_context *conn_req;
+	struct tevent_req *subreq = NULL;
 	struct smb_composite_connect *conn;
 	uint32_t flags;
+	const char *target_hostname = NULL;
+	const char *dest_address = NULL;
+	const char *calling_name = NULL;
 
 	/* composite context allocation and setup */
 	c = composite_create(mem_ctx, io->conn->event_ctx);
@@ -152,12 +158,17 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT
 		return c;
 	}
 
+	if (s->io.creds == NULL) {
+		composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+		return c;
+	}
+
 	/* prepare smb connection parameters: we're connecting to IPC$ share on
 	   remote rpc server */
+	target_hostname = dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
 	conn->in.dest_host = dcerpc_binding_get_string_option(s->io.binding, "host");
 	conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
-	conn->in.called_name =
-		dcerpc_binding_get_string_option(s->io.binding, "target_hostname");
+	conn->in.called_name = target_hostname;
 	if (conn->in.called_name == NULL) {
 		conn->in.called_name = "*SMBSERVER";
 	}
@@ -184,21 +195,113 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT
 		conn->in.fallback_to_anonymous  = false;
 	}
 
-	conn->in.options.min_protocol = PROTOCOL_NT1;
-	conn->in.options.max_protocol = PROTOCOL_NT1;
+	conn->in.options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
+	conn->in.options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
+	if ((flags & DCERPC_SMB1) && (flags & DCERPC_SMB2)) {
+		/* auto */
+	} else if (flags & DCERPC_SMB2) {
+		if (conn->in.options.min_protocol < PROTOCOL_SMB2_02) {
+			conn->in.options.min_protocol = PROTOCOL_SMB2_02;
+		}
+		if (conn->in.options.max_protocol < PROTOCOL_SMB2_02) {
+			conn->in.options.max_protocol = PROTOCOL_LATEST;
+		}
+	} else if (flags & DCERPC_SMB1) {
+		conn->in.options.min_protocol = PROTOCOL_NT1;
+		conn->in.options.max_protocol = PROTOCOL_NT1;
+	} else {
+		/* auto */
+	}
 
 	conn->in.options.signing = lpcfg_client_ipc_signing(lp_ctx);
 
-	/* send smb connect request */
-	conn_req = smb_composite_connect_send(conn, s->io.conn,
-					      s->io.resolve_ctx,
-					      c->event_ctx);
-	if (composite_nomem(conn_req, c)) return c;
+	if (s->conn.in.credentials != NULL) {
+		calling_name = cli_credentials_get_workstation(s->conn.in.credentials);
+	}
+	if (calling_name == NULL) {
+		calling_name = "SMBCLIENT";
+	}
+
+	if (target_hostname == NULL) {
+		target_hostname = conn->in.dest_host;
+	}
+
+	if (is_ipaddress(conn->in.dest_host)) {
+		dest_address = conn->in.dest_host;
+	}
+
+	subreq = smb_connect_nego_send(s,
+				       c->event_ctx,
+				       s->io.resolve_ctx,
+				       &conn->in.options,
+				       conn->in.socket_options,
+				       conn->in.dest_host,
+				       dest_address,
+				       conn->in.dest_ports,
+				       target_hostname,
+				       conn->in.called_name,
+				       calling_name);
+	if (composite_nomem(subreq, c)) return c;
+	tevent_req_set_callback(subreq,
+				continue_smbXcli_connect,
+				c);
 
-	composite_continue(c, conn_req, continue_smb_connect, c);
 	return c;
 }
 
+static void continue_smbXcli_connect(struct tevent_req *subreq)
+{
+	struct composite_context *c =
+		tevent_req_callback_data(subreq,
+		struct composite_context);
+	struct pipe_np_smb_state *s =
+		talloc_get_type_abort(c->private_data,
+		struct pipe_np_smb_state);
+	struct smb_composite_connect *conn = &s->conn;
+	struct composite_context *creq = NULL;
+	enum protocol_types protocol;
+
+	c->status = smb_connect_nego_recv(subreq, s,
+					  &conn->in.existing_conn);
+	TALLOC_FREE(subreq);
+	if (!composite_is_ok(c)) return;
+
+	protocol = smbXcli_conn_protocol(conn->in.existing_conn);
+	if (protocol >= PROTOCOL_SMB2_02) {
+		/*
+		 * continue with smb2 session setup/tree connect
+		 * on the established connection.
+		 */
+		subreq = smb2_connect_send(s, c->event_ctx,
+				conn->in.dest_host,
+				conn->in.dest_ports,
+				conn->in.service,
+				s->io.resolve_ctx,
+				conn->in.credentials,
+				conn->in.fallback_to_anonymous,
+				&conn->in.existing_conn,
+				0, /* previous_session_id */
+				&conn->in.options,
+				conn->in.socket_options,
+				conn->in.gensec_settings);
+		if (composite_nomem(subreq, c)) return;
+		tevent_req_set_callback(subreq, continue_smb2_connect, c);
+		return;
+	}
+
+	/*
+	 * continue with smb1 session setup/tree connect
+	 * on the established connection.
+	 */
+	creq = smb_composite_connect_send(conn, s->io.conn,
+					  s->io.resolve_ctx,
+					  c->event_ctx);
+	if (composite_nomem(creq, c)) return;
+
+	composite_continue(c, creq, continue_smb_connect, c);
+	return;
+}
+
 
 /*
   Receive result of a rpc connection to a rpc pipe on SMB
@@ -238,93 +341,6 @@ static void continue_smb2_connect(struct tevent_req *subreq)
 }
 
 
-/* 
-   Initiate async open of a rpc connection request on SMB2 using
-   the binding structure to determine the endpoint and options
-*/
-static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
-					TALLOC_CTX *mem_ctx,
-					struct dcerpc_pipe_connect *io,
-					struct loadparm_context *lp_ctx)
-{
-	struct composite_context *c;
-	struct pipe_np_smb_state *s;
-	struct tevent_req *subreq;
-	struct smbcli_options options;
-	const char *host;
-	uint32_t flags;
-
-	/* composite context allocation and setup */
-	c = composite_create(mem_ctx, io->conn->event_ctx);
-	if (c == NULL) return NULL;
-
-	s = talloc_zero(c, struct pipe_np_smb_state);
-	if (composite_nomem(s, c)) return c;
-	c->private_data = s;
-
-	s->io = *io;
-
-	if (smbXcli_conn_is_connected(s->io.smb.conn)) {
-		continue_smb_open(c);
-		return c;
-	}
-
-	host = dcerpc_binding_get_string_option(s->io.binding, "host");
-	flags = dcerpc_binding_get_flags(s->io.binding);
-
-	/*
-	 * provide proper credentials - user supplied or anonymous in case this is
-	 * schannel connection
-	 */
-	if (flags & DCERPC_SCHANNEL) {
-		s->io.creds = cli_credentials_init_anon(mem_ctx);
-		if (composite_nomem(s->io.creds, c)) return c;
-	}
-
-	lpcfg_smbcli_options(lp_ctx, &options);
-
-	options.min_protocol = lpcfg_client_ipc_min_protocol(lp_ctx);
-	if (options.min_protocol < PROTOCOL_SMB2_02) {
-		options.min_protocol = PROTOCOL_SMB2_02;
-	}
-	options.max_protocol = lpcfg_client_ipc_max_protocol(lp_ctx);
-	if (options.max_protocol < PROTOCOL_SMB2_02) {
-		options.max_protocol = PROTOCOL_SMB2_02;
-	}
-
-	options.signing = lpcfg_client_ipc_signing(lp_ctx);
-
-	/* send smb2 connect request */
-	subreq = smb2_connect_send(s, c->event_ctx,
-			host,
-			lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "smb2", "ports", NULL),
-			"IPC$",
-			s->io.resolve_ctx,
-			s->io.creds,
-			false, /* fallback_to_anonymous */
-			NULL, /* existing_conn */
-			0, /* previous_session_id */
-			&options,
-			lpcfg_socket_options(lp_ctx),
-			lpcfg_gensec_settings(mem_ctx, lp_ctx));
-	if (composite_nomem(subreq, c)) return c;
-	tevent_req_set_callback(subreq, continue_smb2_connect, c);
-	return c;
-}
-
-
-/*
-  Receive result of a rpc connection to a rpc pipe on SMB2
-*/
-static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context *c)
-{
-	NTSTATUS status = composite_wait(c);
-	
-	talloc_free(c);
-	return status;
-}
-
-
 struct pipe_ip_tcp_state {
 	struct dcerpc_pipe_connect io;
 	const char *localaddr;
@@ -753,7 +769,6 @@ struct pipe_connect_state {
 
 static void continue_map_binding(struct composite_context *ctx);
 static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
-static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
@@ -792,15 +807,12 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
 	struct dcerpc_pipe_connect pc;
 
 	/* potential exits to another stage by sending an async request */
-	struct composite_context *ncacn_np_smb2_req;
 	struct composite_context *ncacn_np_smb_req;
 	struct composite_context *ncacn_ip_tcp_req;
 	struct composite_context *ncacn_http_req;
 	struct composite_context *ncacn_unix_req;
 	struct composite_context *ncalrpc_req;
 	enum dcerpc_transport_t transport;
-	enum protocol_types min_ipc_protocol;
-	uint32_t flags;
 
 	/* dcerpc pipe connect input parameters */
 	ZERO_STRUCT(pc);
@@ -811,29 +823,16 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
 	pc.resolve_ctx  = lpcfg_resolve_context(s->lp_ctx);
 
 	transport = dcerpc_binding_get_transport(s->binding);
-	flags = dcerpc_binding_get_flags(s->binding);
-
-	min_ipc_protocol = lpcfg_client_ipc_min_protocol(s->lp_ctx);
-	if (min_ipc_protocol >= PROTOCOL_SMB2_02) {
-		flags |= DCERPC_SMB2;
-	}
 
 	/* connect dcerpc pipe depending on required transport */
 	switch (transport) {
 	case NCACN_NP:
-		if (flags & DCERPC_SMB2) {
-			/* new varient of SMB a.k.a. SMB2 */
-			ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc, s->lp_ctx);
-			composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
-			return;
-
-		} else {
-			/* good old ordinary SMB */
-			ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
-			composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
-			return;
-		}
-		break;
+		/*
+		 * SMB1/2/3...
+		 */
+		ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
+		composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
+		return;
 
 	case NCACN_IP_TCP:
 		ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
@@ -866,24 +865,6 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
 }
 
 
-/*
-  Stage 3 of pipe_connect_b: Receive result of pipe connect request on
-  named pipe on smb2
-*/
-static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
-{
-	struct composite_context *c = talloc_get_type(ctx->async.private_data,
-						      struct composite_context);
-	struct pipe_connect_state *s = talloc_get_type(c->private_data,
-						       struct pipe_connect_state);
-
-	c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
-	if (!composite_is_ok(c)) return;
-
-	continue_pipe_connect(c, s);
-}
-
-
 /*
   Stage 3 of pipe_connect_b: Receive result of pipe connect request on
   named pipe on smb
-- 
2.17.1


From 56c826f3dfbe41f21d7673072b9269579e8b190f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 19 Jul 2018 07:34:11 +0200
Subject: [PATCH 15/16] s3:selftest: run rpc.lsa.lookupsids also with explicit
 [smb1] and [smb2]

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

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/selftest/tests.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index a061483c5f5f..bf0ba2a44546 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -581,7 +581,7 @@ for t in tests:
 
 
 test = 'rpc.lsa.lookupsids'
-auth_options = ["", "ntlm", "spnego", "spnego,ntlm" ]
+auth_options = ["", "ntlm", "spnego", "spnego,ntlm", "spnego,smb1", "spnego,smb2"]
 signseal_options = ["", ",connect", ",packet", ",sign", ",seal"]
 endianness_options = ["", ",bigendian"]
 for s in signseal_options:
-- 
2.17.1


From 3637204a8f4a6e4f4d14c45d15f6ad9252d14134 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Sat, 24 Feb 2018 14:34:44 +0200
Subject: [PATCH 16/16] samba-tool trust: support discovery via netr_GetDcName

In case a remote DC does not support netr_DsRGetDCNameEx2(),
use netr_GetDcName() instead.

This should help with FreeIPA where embedded smbd runs as a domain
controller but does not implement full Active Directory compatibility.

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

Signed-off-by: Alexander Bokovoy <ab at samba.org>
---
 python/samba/netcmd/domain.py | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 555462c9615c..becbc498b9e8 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -1876,6 +1876,15 @@ class DomainTrustCommand(Command):
 
         return (policy, info)
 
+    def get_netlogon_dc_unc(self, conn, server, domain):
+        try:
+            info = conn.netr_DsRGetDCNameEx2(server,
+                                             None, 0, None, None, None,
+                                             netlogon.DS_RETURN_DNS_NAME)
+            return info.dc_unc
+        except RuntimeError:
+            return conn.netr_GetDcName(server, domain)
+
     def get_netlogon_dc_info(self, conn, server):
         info = conn.netr_DsRGetDCNameEx2(server,
                                          None, 0, None, None, None,
@@ -2509,7 +2518,8 @@ class cmd_domain_trust_create(DomainTrustCommand):
                 raise self.RemoteRuntimeError(self, error, "failed to connect netlogon server")
 
             try:
-                remote_netlogon_info = self.get_netlogon_dc_info(remote_netlogon, remote_server)
+                remote_netlogon_dc_unc = self.get_netlogon_dc_unc(remote_netlogon,
+                                                                  remote_server, domain)
             except RuntimeError as error:
                 raise self.RemoteRuntimeError(self, error, "failed to get netlogon dc info")
 
@@ -2659,9 +2669,9 @@ class cmd_domain_trust_create(DomainTrustCommand):
                         # this triggers netr_GetForestTrustInformation to our domain.
                         # and lsaRSetForestTrustInformation() remotely, but new top level
                         # names are disabled by default.
-                        remote_forest_info = remote_netlogon.netr_DsRGetForestTrustInformation(remote_netlogon_info.dc_unc,
-                                                                      local_lsa_info.dns_domain.string,
-                                                                      netlogon.DS_GFTI_UPDATE_TDO)
+                        remote_forest_info = remote_netlogon.netr_DsRGetForestTrustInformation(remote_netlogon_dc_unc,
+                                                                                               local_lsa_info.dns_domain.string,
+                                                                                               netlogon.DS_GFTI_UPDATE_TDO)
                     except RuntimeError as error:
                         raise self.RemoteRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
 
@@ -2712,10 +2722,10 @@ class cmd_domain_trust_create(DomainTrustCommand):
                 if remote_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
                     self.outf.write("Validating incoming trust...\n")
                     try:
-                        remote_trust_verify = remote_netlogon.netr_LogonControl2Ex(remote_netlogon_info.dc_unc,
-                                                                      netlogon.NETLOGON_CONTROL_TC_VERIFY,
-                                                                      2,
-                                                                      local_lsa_info.dns_domain.string)
+                        remote_trust_verify = remote_netlogon.netr_LogonControl2Ex(remote_netlogon_dc_unc,
+                                                                                   netlogon.NETLOGON_CONTROL_TC_VERIFY,
+                                                                                   2,
+                                                                                   local_lsa_info.dns_domain.string)
                     except RuntimeError as error:
                         raise self.RemoteRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
 
-- 
2.17.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20180724/a6eba99b/signature.sig>


More information about the samba-technical mailing list