[PATCH] Add remote arch caching

Ralph Boehme slow at samba.org
Mon Apr 25 13:13:50 UTC 2016


Hi!

For a reliable %a remote arch variable, we need some sort of remote
arch caching.

Remote arch caching only works for SMB1 NEGPROT by fingerprinting the
supported dialects in an SMB1 NEGPROT. Luckily, many clients do a SMB1
NEGPORT and upgrade to SMB2 or higher if available, so remote arch
detection works for SMB2 connections as well.

Unfortunately, after a disconnect, clients may choose to do a direct
SMB2 NEGPROT. To workaround this, cache the remote arch in the
gencache, using the client guid as db key. This means it only works
for SMB 2_10 or higher.

The idea is that whenever we get a direct SMB2 NEGPROT where the
remote arch wasn't set at the SMB1 stage, we can then try to see if a
value is cached for the client's guid.

When a user logs the cache entry is deleted.

Cheerio!
-slow
-------------- next part --------------
From 587a45993b83b1296b2be3f0f955361d625dd292 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Apr 2016 17:39:26 +0200
Subject: [PATCH 1/4] s3/lib: rework get_remote_arch_str() to use an array

By using C99 designated array initializers we can simplify the code and
remove the dependency on initializers appearing in a particular order.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/include/smb.h |  2 +-
 source3/lib/util.c    | 73 ++++++++++++++++++---------------------------------
 2 files changed, 27 insertions(+), 48 deletions(-)

diff --git a/source3/include/smb.h b/source3/include/smb.h
index 7eeef88..dec3189 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -529,7 +529,7 @@ http://msdn.microsoft.com/en-us/library/cc246334(PROT.13).aspx
 #define NO_SUBSTREAMS		0x2
 #define NO_REPARSETAG		0x4
 
-/* Remote architectures we know about. */
+/* Remote architectures we know about, keep in sync with remote_arch_strings */
 enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
 			RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_VISTA,
 			RA_SAMBA, RA_CIFSFS, RA_WINXP64, RA_OSX};
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 2895c14..376924e 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1230,14 +1230,25 @@ void ra_lanman_string( const char *native_lanman )
 		set_remote_arch( RA_WIN2K3 );
 }
 
-static const char *remote_arch_str;
+static const char *remote_arch_strings[] = {
+	[RA_UNKNOWN] =	"UNKNOWN",
+	[RA_WFWG] =	"WfWg",
+	[RA_OS2] =	"OS2",
+	[RA_WIN95] =	"Win95",
+	[RA_WINNT] =	"WinNT",
+	[RA_WIN2K] =	"Win2K",
+	[RA_WINXP] =	"WinXP",
+	[RA_WIN2K3] =	"Win2K3",
+	[RA_VISTA] =	"Vista",
+	[RA_SAMBA] =	"Samba",
+	[RA_CIFSFS] =	"CIFSFS",
+	[RA_WINXP64] =	"WinXP64",
+	[RA_OSX] =	"OSX",
+};
 
 const char *get_remote_arch_str(void)
 {
-	if (!remote_arch_str) {
-		return "UNKNOWN";
-	}
-	return remote_arch_str;
+	return remote_arch_strings[ra_type];
 }
 
 /*******************************************************************
@@ -1246,52 +1257,20 @@ const char *get_remote_arch_str(void)
 
 void set_remote_arch(enum remote_arch_types type)
 {
-	ra_type = type;
-	switch( type ) {
-	case RA_WFWG:
-		remote_arch_str = "WfWg";
-		break;
-	case RA_OS2:
-		remote_arch_str = "OS2";
-		break;
-	case RA_WIN95:
-		remote_arch_str = "Win95";
-		break;
-	case RA_WINNT:
-		remote_arch_str = "WinNT";
-		break;
-	case RA_WIN2K:
-		remote_arch_str = "Win2K";
-		break;
-	case RA_WINXP:
-		remote_arch_str = "WinXP";
-		break;
-	case RA_WINXP64:
-		remote_arch_str = "WinXP64";
-		break;
-	case RA_WIN2K3:
-		remote_arch_str = "Win2K3";
-		break;
-	case RA_VISTA:
-		remote_arch_str = "Vista";
-		break;
-	case RA_SAMBA:
-		remote_arch_str = "Samba";
-		break;
-	case RA_CIFSFS:
-		remote_arch_str = "CIFSFS";
-		break;
-	case RA_OSX:
-		remote_arch_str = "OSX";
-		break;
-	default:
+	if (ra_type >= sizeof(remote_arch_strings)) {
+		/*
+		 * This protects against someone adding values to enum
+		 * remote_arch_types without updating
+		 * remote_arch_strings array.
+		 */
+		DBG_ERR("Remote arch info out of sync [%d] missing\n", ra_type);
 		ra_type = RA_UNKNOWN;
-		remote_arch_str = "UNKNOWN";
-		break;
+		return;
 	}
 
+	ra_type = type;
 	DEBUG(10,("set_remote_arch: Client arch is \'%s\'\n",
-				remote_arch_str));
+		  get_remote_arch_str()));
 }
 
 /*******************************************************************
-- 
2.5.0


From 5ee42eac75938316ce0322e22c568d15f5793b0c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Apr 2016 17:55:11 +0200
Subject: [PATCH 2/4] s3/lib: add get_remote_arch_from_str()

This will be used when fetching remote arch from gencache.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/include/proto.h |  1 +
 source3/lib/util.c      | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index afbbff0..8baf9d9 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -389,6 +389,7 @@ bool fcntl_getlock(int fd, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppi
 bool is_myname(const char *s);
 void ra_lanman_string( const char *native_lanman );
 const char *get_remote_arch_str(void);
+enum remote_arch_types get_remote_arch_from_str(const char *remote_arch_string);
 void set_remote_arch(enum remote_arch_types type);
 enum remote_arch_types get_remote_arch(void);
 const char *tab_depth(int level, int depth);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 376924e..53a6d79 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1251,6 +1251,16 @@ const char *get_remote_arch_str(void)
 	return remote_arch_strings[ra_type];
 }
 
+enum remote_arch_types get_remote_arch_from_str(const char *remote_arch_string)
+{
+	for (int i = 0; i < sizeof(remote_arch_strings); i++) {
+		if (strcmp(remote_arch_string, remote_arch_strings[i]) == 0) {
+			return i;
+		}
+	}
+	return RA_UNKNOWN;
+}
+
 /*******************************************************************
  Set the horrid remote_arch string based on an enum.
 ********************************************************************/
-- 
2.5.0


From 24e2e873bd24886a0bf316deabfa4442c1e34eae Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Apr 2016 17:42:55 +0200
Subject: [PATCH 3/4] s3/lib: add remote arch caching

This allows caching the remote arch string in gencache. A subsequent
commit will use this in SMB2 negprot.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/include/proto.h |   4 ++
 source3/lib/util.c      | 105 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 8baf9d9..05efd2e 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -392,6 +392,10 @@ const char *get_remote_arch_str(void);
 enum remote_arch_types get_remote_arch_from_str(const char *remote_arch_string);
 void set_remote_arch(enum remote_arch_types type);
 enum remote_arch_types get_remote_arch(void);
+bool remote_arch_cache_update(TALLOC_CTX *mem_ctx,
+			      const struct GUID *client_guid);
+bool remote_arch_cache_delete(TALLOC_CTX *mem_ctx,
+			      const struct GUID *client_guid);
 const char *tab_depth(int level, int depth);
 int str_checksum(const char *s);
 void zero_free(void *p, size_t size);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 53a6d79..9fe8948 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1292,6 +1292,111 @@ enum remote_arch_types get_remote_arch(void)
 	return ra_type;
 }
 
+#define RA_CACHE_TTL 7*24*3600
+
+static char *remote_arch_cache_key(TALLOC_CTX *mem_ctx,
+				   const struct GUID *client_guid)
+{
+	char *guid_string = NULL;
+	char *key = NULL;
+
+	guid_string = GUID_string(mem_ctx, client_guid);
+	if (guid_string == NULL) {
+		return NULL;
+	}
+
+	key = talloc_asprintf(mem_ctx, "RA/%s", guid_string);
+	TALLOC_FREE(guid_string);
+	if (key == NULL) {
+		return NULL;
+	}
+
+	return key;
+}
+
+static bool remote_arch_cache_get(TALLOC_CTX *mem_ctx,
+				  const struct GUID *client_guid)
+{
+	bool found;
+	char *ra_key = NULL;
+	char *ra_str = NULL;
+	enum remote_arch_types ra;
+
+	ra_key = remote_arch_cache_key(mem_ctx, client_guid);
+	if (ra_key == NULL) {
+		return false;
+	}
+
+	found = gencache_get(ra_key, mem_ctx, &ra_str, NULL);
+	TALLOC_FREE(ra_key);
+	if (!found) {
+		return true;
+	}
+
+	ra = get_remote_arch_from_str(ra_str);
+	if (ra != RA_UNKNOWN) {
+		DBG_INFO("Settting remote arch [%s] from cache\n", ra_str);
+		set_remote_arch(ra);
+	}
+
+	return true;
+}
+
+static bool remote_arch_cache_set(TALLOC_CTX *mem_ctx,
+				  const struct GUID *client_guid)
+{
+	bool ok;
+	char *ra_key = NULL;
+
+	if (get_remote_arch() == RA_UNKNOWN) {
+		return true;
+	}
+
+	ra_key = remote_arch_cache_key(mem_ctx, client_guid);
+	if (ra_key == NULL) {
+		return false;
+	}
+
+	ok = gencache_set(ra_key, get_remote_arch_str(),
+			  time(NULL) + RA_CACHE_TTL);
+	TALLOC_FREE(ra_key);
+	if (!ok) {
+		return false;
+	}
+
+	return true;
+}
+
+bool remote_arch_cache_update(TALLOC_CTX *mem_ctx,
+			      const struct GUID *client_guid)
+{
+	if (get_remote_arch() == RA_UNKNOWN) {
+		return remote_arch_cache_get(mem_ctx, client_guid);
+	}
+
+	return remote_arch_cache_set(mem_ctx, client_guid);
+}
+
+bool remote_arch_cache_delete(TALLOC_CTX *mem_ctx,
+			      const struct GUID *client_guid)
+{
+	bool ok;
+	char *ra_key = NULL;
+
+	ra_key = remote_arch_cache_key(mem_ctx, client_guid);
+	if (ra_key == NULL) {
+		return false;
+	}
+
+	ok = gencache_del(ra_key);
+	TALLOC_FREE(ra_key);
+	if (!ok) {
+		return false;
+	}
+
+	return true;
+}
+
 const char *tab_depth(int level, int depth)
 {
 	if( CHECK_DEBUGLVL(level) ) {
-- 
2.5.0


From e734d66813d24910b42c9e8f44f84a8604d08b1b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 13 Apr 2016 17:44:26 +0200
Subject: [PATCH 4/4] smbd: use remote arch caching

We're using the client guid as gencache db key, so this can only be used
with SMB 2_10 or higher.

The idea is that whenever we get a direct SMB2 negprot where the remote
arch wasn't set at the smb1 stage, we can then try to see if a value is
cached for the client's guid.

When a user logs the cache entry is deleted.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_negprot.c   | 13 ++++++++++++-
 source3/smbd/smb2_sesssetup.c | 11 +++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
index 9c03b2c..d936e31 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -162,6 +162,7 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 	uint32_t max_write = lp_smb2_max_write();
 	NTTIME now = timeval_to_nttime(&req->request_time);
 	bool signing_required = true;
+	bool ok;
 
 	status = smbd_smb2_request_verify_sizes(req, 0x24);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -260,6 +261,17 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 		}
 	}
 
+	if ((dialect != SMB2_DIALECT_REVISION_2FF) &&
+	    (protocol >= PROTOCOL_SMB2_10) &&
+	    !GUID_all_zero(&in_guid))
+	{
+		ok = remote_arch_cache_update(req, &in_guid);
+		if (!ok) {
+			return smbd_smb2_request_error(
+				req, NT_STATUS_UNSUCCESSFUL);
+		}
+	}
+
 	switch (get_remote_arch()) {
 	case RA_VISTA:
 	case RA_SAMBA:
@@ -532,7 +544,6 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 		static const uint8_t zeros[8];
 		size_t pad = 0;
 		size_t ofs;
-		bool ok;
 
 		outdyn = data_blob_dup_talloc(req, security_buffer);
 		if (outdyn.length != security_buffer.length) {
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index 78bda7b..002e9df 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -1305,6 +1305,9 @@ static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq)
 	struct smbd_smb2_logoff_state *state = tevent_req_data(
 		req, struct smbd_smb2_logoff_state);
 	NTSTATUS status;
+	bool ok;
+	const struct GUID *client_guid =
+		&state->smb2req->session->client->connections->smb2.client.guid;
 
 	status = smb2srv_session_shutdown_recv(subreq);
 	if (tevent_req_nterror(req, status)) {
@@ -1312,6 +1315,14 @@ static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq)
 	}
 	TALLOC_FREE(subreq);
 
+	if (!GUID_all_zero(client_guid)) {
+		ok = remote_arch_cache_delete(state, client_guid);
+		if (!ok) {
+			/* Most likely not an error, but not in cache */
+			DBG_DEBUG("Deletion from remote arch cache failed\n");
+		}
+	}
+
 	/*
 	 * As we've been awoken, we may have changed
 	 * uid in the meantime. Ensure we're still
-- 
2.5.0



More information about the samba-technical mailing list