[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Sat Jul 19 04:52:03 MDT 2014


The branch, master has been updated
       via  d90f332 s4:torture/rpc: add rpc.netlogon.ServerReqChallengeGlobal
       via  321ebc9 s4:rpc_server/netlogon: keep a global challenge table
      from  4580702 lib/util: move memcache.[ch] to the toplevel 'samba-util' library

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit d90f3323ee001080645dcd25da8b8ce1367b1377
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jul 17 16:05:12 2014 +0200

    s4:torture/rpc: add rpc.netlogon.ServerReqChallengeGlobal
    
    This demonstrates that the challenge table should be global.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10723
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Sat Jul 19 12:51:39 CEST 2014 on sn-devel-104

commit 321ebc99b5a00f82265aee741a48aa84b214d6e8
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jul 17 14:20:58 2014 +0200

    s4:rpc_server/netlogon: keep a global challenge table
    
    Some clients call netr_ServerReqChallenge() and netr_ServerAuthenticate3()
    on different connections. This works against Windows DCs as they
    have a global challenge table.
    
    A VMware provisioning task for Windows VMs seemy to rely on this behavior.
    
    As a fallback we're storing the challenge in a global memcache with a fixed
    size. This should allow these strange clients to work against a
    Samba AD DC.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10723
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 source4/rpc_server/netlogon/dcerpc_netlogon.c |   91 +++++++++++++++++++++++-
 source4/torture/rpc/netlogon.c                |   73 ++++++++++++++++++++
 2 files changed, 160 insertions(+), 4 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index c7fed22..49eb5c3 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -27,6 +27,7 @@
 #include "auth/auth_sam_reply.h"
 #include "dsdb/samdb/samdb.h"
 #include "../lib/util/util_ldb.h"
+#include "../lib/util/memcache.h"
 #include "../libcli/auth/schannel.h"
 #include "libcli/security/security.h"
 #include "param/param.h"
@@ -39,6 +40,8 @@
 #include "librpc/gen_ndr/ndr_irpc.h"
 #include "lib/socket/netif.h"
 
+static struct memcache *global_challenge_table;
+
 struct netlogon_server_pipe_state {
 	struct netr_Credential client_challenge;
 	struct netr_Credential server_challenge;
@@ -49,9 +52,27 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
 {
 	struct netlogon_server_pipe_state *pipe_state =
 		talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+	DATA_BLOB key, val;
 
 	ZERO_STRUCTP(r->out.return_credentials);
 
+	if (global_challenge_table == NULL) {
+		/*
+		 * We maintain a global challenge table
+		 * with a fixed size (8k)
+		 *
+		 * This is required for the strange clients
+		 * which use different connections for
+		 * netr_ServerReqChallenge() and netr_ServerAuthenticate3()
+		 *
+		 */
+		global_challenge_table = memcache_init(talloc_autofree_context(),
+						       8192);
+		if (global_challenge_table == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
 	/* destroyed on pipe shutdown */
 
 	if (pipe_state) {
@@ -71,6 +92,11 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
 
 	dce_call->context->private_data = pipe_state;
 
+	key = data_blob_string_const(r->in.computer_name);
+	val = data_blob_const(pipe_state, sizeof(*pipe_state));
+
+	memcache_add(global_challenge_table, SINGLETON_CACHE, key, val);
+
 	return NT_STATUS_OK;
 }
 
@@ -79,6 +105,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
 {
 	struct netlogon_server_pipe_state *pipe_state =
 		talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+	DATA_BLOB challenge_key;
+	bool challenge_valid = false;
+	struct netlogon_server_pipe_state challenge;
 	struct netlogon_creds_CredentialState *creds;
 	struct ldb_context *sam_ctx;
 	struct samr_Password *mach_pwd;
@@ -100,6 +129,57 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
 	ZERO_STRUCTP(r->out.return_credentials);
 	*r->out.rid = 0;
 
+	challenge_key = data_blob_string_const(r->in.computer_name);
+	if (pipe_state != NULL) {
+		dce_call->context->private_data = NULL;
+
+		/*
+		 * If we had a challenge remembered on the connection
+		 * consider this for usage. This can't be cleanup
+		 * by other clients.
+		 *
+		 * This is the default code path for typical clients
+		 * which call netr_ServerReqChallenge() and
+		 * netr_ServerAuthenticate3() on the same dcerpc connection.
+		 */
+		challenge = *pipe_state;
+		TALLOC_FREE(pipe_state);
+		challenge_valid = true;
+	} else {
+		DATA_BLOB val;
+		bool ok;
+
+		/*
+		 * Fallback and try to get the challenge from
+		 * the global cache.
+		 *
+		 * If too many clients are using this code path,
+		 * they may destroy their cache entries as the
+		 * global_challenge_table memcache has a fixed size.
+		 *
+		 * Note: this handles global_challenge_table == NULL fine
+		 */
+		ok = memcache_lookup(global_challenge_table, SINGLETON_CACHE,
+				     challenge_key, &val);
+		if (ok && val.length == sizeof(challenge)) {
+			memcpy(&challenge, val.data, sizeof(challenge));
+			challenge_valid = true;
+		} else {
+			ZERO_STRUCT(challenge);
+		}
+	}
+
+	/*
+	 * At this point we can cleanup the cache entry,
+	 * if we fail the client needs to call netr_ServerReqChallenge
+	 * again.
+	 *
+	 * Note: this handles global_challenge_table == NULL
+	 * and also a non existing record just fine.
+	 */
+	memcache_delete(global_challenge_table,
+			SINGLETON_CACHE, challenge_key);
+
 	server_flags = NETLOGON_NEG_ACCOUNT_LOCKOUT |
 		       NETLOGON_NEG_PERSISTENT_SAMREPL |
 		       NETLOGON_NEG_ARCFOUR |
@@ -273,8 +353,11 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
-	if (!pipe_state) {
-		DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
+	if (!challenge_valid) {
+		DEBUG(1, ("No challenge requested by client [%s/%s], "
+			  "cannot authenticate\n",
+			  r->in.computer_name,
+			  r->in.account_name));
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
@@ -282,8 +365,8 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
 					   r->in.account_name,
 					   r->in.computer_name,
 					   r->in.secure_channel_type,
-					   &pipe_state->client_challenge,
-					   &pipe_state->server_challenge,
+					   &challenge.client_challenge,
+					   &challenge.server_challenge,
 					   mach_pwd,
 					   r->in.credentials,
 					   r->out.return_credentials,
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index 90bfe7e..76135a3 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -1103,6 +1103,78 @@ static bool test_invalidAuthenticate2(struct torture_context *tctx,
 	return true;
 }
 
+static bool test_ServerReqChallengeGlobal(struct torture_context *tctx,
+					  struct dcerpc_pipe *p1,
+					  struct cli_credentials *machine_credentials)
+{
+	uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+	struct netr_ServerReqChallenge r;
+	struct netr_ServerAuthenticate3 a;
+	struct netr_Credential credentials1, credentials2, credentials3;
+	struct netlogon_creds_CredentialState *creds;
+	struct samr_Password mach_password;
+	uint32_t rid;
+	const char *machine_name;
+	const char *plain_pass;
+	struct dcerpc_binding_handle *b1 = p1->binding_handle;
+	struct dcerpc_pipe *p2 = NULL;
+	struct dcerpc_binding_handle *b2 = NULL;
+
+	machine_name = cli_credentials_get_workstation(machine_credentials);
+	plain_pass = cli_credentials_get_password(machine_credentials);
+
+	torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+	torture_assert_ntstatus_ok(tctx,
+		dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+				      &ndr_table_netlogon,
+				      machine_credentials,
+				      tctx->ev, tctx->lp_ctx),
+		"dcerpc_pipe_connect_b failed");
+	b2 = p2->binding_handle;
+
+	r.in.server_name = NULL;
+	r.in.computer_name = machine_name;
+	r.in.credentials = &credentials1;
+	r.out.return_credentials = &credentials2;
+
+	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+		"ServerReqChallenge failed on b1");
+	torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+	E_md4hash(plain_pass, mach_password.hash);
+
+	a.in.server_name = NULL;
+	a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+	a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+	a.in.computer_name = machine_name;
+	a.in.negotiate_flags = &flags;
+	a.in.credentials = &credentials3;
+	a.out.return_credentials = &credentials3;
+	a.out.negotiate_flags = &flags;
+	a.out.rid = &rid;
+
+	creds = netlogon_creds_client_init(tctx, a.in.account_name,
+					   a.in.computer_name,
+					   a.in.secure_channel_type,
+					   &credentials1, &credentials2,
+					   &mach_password, &credentials3,
+					   flags);
+
+	torture_assert(tctx, creds != NULL, "memory allocation");
+
+	torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+		"ServerAuthenticate3 failed on b2");
+	torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b2");
+	torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+	return true;
+}
+
 static bool test_SamLogon_NULL_domain(struct torture_context *tctx,
 				      struct dcerpc_pipe *p,
 				      struct cli_credentials *credentials)
@@ -3943,6 +4015,7 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx)
 	torture_rpc_tcase_add_test(tcase, "LogonUasLogoff", test_LogonUasLogoff);
 	torture_rpc_tcase_add_test_creds(tcase, "SamLogon", test_SamLogon);
 	torture_rpc_tcase_add_test_creds(tcase, "invalidAuthenticate2", test_invalidAuthenticate2);
+	torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeGlobal", test_ServerReqChallengeGlobal);
 	torture_rpc_tcase_add_test_creds(tcase, "SetPassword", test_SetPassword);
 	torture_rpc_tcase_add_test_creds(tcase, "SetPassword2", test_SetPassword2);
 	torture_rpc_tcase_add_test_creds(tcase, "SetPassword2_AES", test_SetPassword2_AES);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list