[PATCH] Cache lookupname/sid in gencache

Volker Lendecke Volker.Lendecke at SerNet.DE
Tue Nov 21 08:07:03 UTC 2017


Hi!

winbindd_cache.tdb is tightly coupled with a specific domain. For
lookupname and lookupsid this is not right, we can ask "our" DC for
names in any trusted domain. This patchset moves the cache for
lookupsid and lookupname into gencache.

Review appreciated!

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 437f7f8673462f52670ba0ba620bfd98e6ee4bd2 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 Aug 2017 17:22:34 +0200
Subject: [PATCH 01/10] lib: Pass in "strv_len" to strv_valid_entry

Preparation for a later commit

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/strv.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/lib/util/strv.c b/lib/util/strv.c
index 99ce76f..864a3e5 100644
--- a/lib/util/strv.c
+++ b/lib/util/strv.c
@@ -62,27 +62,23 @@ int strv_append(TALLOC_CTX *mem_ctx, char **strv, const char *src)
 	return _strv_append(mem_ctx, strv, src, talloc_array_length(src));
 }
 
-static bool strv_valid_entry(const char *strv, const char *entry,
-			     size_t *strv_len, size_t *entry_len)
+static bool strv_valid_entry(const char *strv, size_t strv_len,
+			     const char *entry, size_t *entry_len)
 {
-	size_t len;
-
-	len = talloc_array_length(strv);
-	if (len == 0) {
+	if (strv_len == 0) {
 		return false;
 	}
-	if (strv[len-1] != '\0') {
+	if (strv[strv_len-1] != '\0') {
 		return false;
 	}
 
 	if (entry < strv) {
 		return false;
 	}
-	if (entry >= (strv+len)) {
+	if (entry >= (strv+strv_len)) {
 		return false;
 	}
 
-	*strv_len = len;
 	*entry_len = strlen(entry);
 
 	return true;
@@ -90,17 +86,18 @@ static bool strv_valid_entry(const char *strv, const char *entry,
 
 char *strv_next(char *strv, const char *entry)
 {
-	size_t len, entry_len;
+	size_t len = talloc_array_length(strv);
+	size_t entry_len;
 	char *result;
 
 	if (entry == NULL) {
-		if (strv_valid_entry(strv, strv, &len, &entry_len)) {
+		if (strv_valid_entry(strv, len, strv, &entry_len)) {
 			return strv;
 		}
 		return NULL;
 	}
 
-	if (!strv_valid_entry(strv, entry, &len, &entry_len)) {
+	if (!strv_valid_entry(strv, len, entry, &entry_len)) {
 		return NULL;
 	}
 	result = &strv[entry - strv]; /* avoid const problems with this stmt */
@@ -139,13 +136,14 @@ char *strv_find(char *strv, const char *entry)
 
 void strv_delete(char **strv, char *entry)
 {
-	size_t len, entry_len;
+	size_t len = talloc_array_length(*strv);
+	size_t entry_len;
 
 	if (entry == NULL) {
 		return;
 	}
 
-	if (!strv_valid_entry(*strv, entry, &len, &entry_len)) {
+	if (!strv_valid_entry(*strv, len, entry, &entry_len)) {
 		return;
 	}
 	entry_len += 1;
-- 
1.9.1


From 0f0c097ef5e5d17857f4edbf592a3de89efc244e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 Aug 2017 17:32:50 +0200
Subject: [PATCH 02/10] lib: Only call strlen if necessary in strv

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/strv.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/util/strv.c b/lib/util/strv.c
index 864a3e5..328f561 100644
--- a/lib/util/strv.c
+++ b/lib/util/strv.c
@@ -79,7 +79,9 @@ static bool strv_valid_entry(const char *strv, size_t strv_len,
 		return false;
 	}
 
-	*entry_len = strlen(entry);
+	if (entry_len != NULL) {
+		*entry_len = strlen(entry);
+	}
 
 	return true;
 }
@@ -91,7 +93,7 @@ char *strv_next(char *strv, const char *entry)
 	char *result;
 
 	if (entry == NULL) {
-		if (strv_valid_entry(strv, len, strv, &entry_len)) {
+		if (strv_valid_entry(strv, len, strv, NULL)) {
 			return strv;
 		}
 		return NULL;
-- 
1.9.1


From 59aeeb71abdbc921cc11be93d96bb9da8e500d88 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 Aug 2017 17:34:25 +0200
Subject: [PATCH 03/10] lib: Allow parsing a strv from a non-talloc const buf

This will allow parsing a tdb record without having to talloc_memdup it

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/strv.c | 26 +++++++++++++++++---------
 lib/util/strv.h |  2 ++
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/lib/util/strv.c b/lib/util/strv.c
index 328f561..83d84d9 100644
--- a/lib/util/strv.c
+++ b/lib/util/strv.c
@@ -86,29 +86,37 @@ static bool strv_valid_entry(const char *strv, size_t strv_len,
 	return true;
 }
 
-char *strv_next(char *strv, const char *entry)
+const char *strv_len_next(const char *strv, size_t strv_len,
+			  const char *entry)
 {
-	size_t len = talloc_array_length(strv);
 	size_t entry_len;
-	char *result;
 
 	if (entry == NULL) {
-		if (strv_valid_entry(strv, len, strv, NULL)) {
+		if (strv_valid_entry(strv, strv_len, strv, NULL)) {
 			return strv;
 		}
 		return NULL;
 	}
 
-	if (!strv_valid_entry(strv, len, entry, &entry_len)) {
+	if (!strv_valid_entry(strv, strv_len, entry, &entry_len)) {
 		return NULL;
 	}
-	result = &strv[entry - strv]; /* avoid const problems with this stmt */
-	result += entry_len + 1;
 
-	if (result >= (strv + len)) {
+	entry += entry_len+1;
+
+	if (entry >= (strv + strv_len)) {
 		return NULL;
 	}
-	return result;
+	return entry;
+}
+
+char *strv_next(char *strv, const char *entry)
+{
+	size_t len = talloc_array_length(strv);
+	const char *result;
+
+	result = strv_len_next(strv, len, entry);
+	return discard_const_p(char, result);
 }
 
 size_t strv_count(char *strv)
diff --git a/lib/util/strv.h b/lib/util/strv.h
index 398e8ea..89f0402 100644
--- a/lib/util/strv.h
+++ b/lib/util/strv.h
@@ -26,6 +26,8 @@ int strv_add(TALLOC_CTX *mem_ctx, char **strv, const char *string);
 int strv_addn(TALLOC_CTX *mem_ctx, char **strv, const char *src, size_t srclen);
 int strv_append(TALLOC_CTX *mem_ctx, char **strv, const char *src);
 char *strv_next(char *strv, const char *entry);
+const char *strv_len_next(const char *strv, size_t strv_len,
+			  const char *entry);
 char *strv_find(char *strv, const char *entry);
 size_t strv_count(char *strv);
 void strv_delete(char **strv, char *entry);
-- 
1.9.1


From 9629f0045e8c16a6aead51a21a08a34356bd0654 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 Aug 2017 17:52:40 +0200
Subject: [PATCH 04/10] lib: Pass blob instead of &blob to
 gencache_set_data_blob

Passing a whole DATA_BLOB is cheap enough to simplify the callers: A caller
does not have to create a separate variable.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/gencache.c            | 12 ++++++------
 source3/lib/gencache.h            |  2 +-
 source3/libsmb/dsgetdcname.c      |  7 ++++---
 source3/torture/torture.c         |  4 ++--
 source3/winbindd/wb_dsgetdcname.c |  2 +-
 5 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c
index e73d1c5..ab12fc1 100644
--- a/source3/lib/gencache.c
+++ b/source3/lib/gencache.c
@@ -252,7 +252,7 @@ static int last_stabilize_parser(TDB_DATA key, TDB_DATA data,
  * @retval false on failure
  **/
 
-bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
+bool gencache_set_data_blob(const char *keystr, DATA_BLOB blob,
 			    time_t timeout)
 {
 	int ret;
@@ -268,7 +268,7 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 		return false;
 	}
 
-	if ((keystr == NULL) || (blob == NULL)) {
+	if ((keystr == NULL) || (blob.data == NULL)) {
 		return false;
 	}
 
@@ -276,7 +276,7 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 		return false;
 	}
 
-	if ((timeout != 0) && gencache_have_val(keystr, blob, timeout)) {
+	if ((timeout != 0) && gencache_have_val(keystr, &blob, timeout)) {
 		DEBUG(10, ("Did not store value for %s, we already got it\n",
 			   keystr));
 		return true;
@@ -287,12 +287,12 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
 	if (hdr_len == -1) {
 		return false;
 	}
-	if ((blob->length + (size_t)hdr_len) < blob->length) {
+	if ((blob.length + (size_t)hdr_len) < blob.length) {
 		return false;
 	}
 
 	dbufs[0] = (TDB_DATA) { .dptr = (uint8_t *)hdr, .dsize = hdr_len };
-	dbufs[1] = (TDB_DATA) { .dptr = blob->data, .dsize = blob->length };
+	dbufs[1] = (TDB_DATA) { .dptr = blob.data, .dsize = blob.length };
 
 	DEBUG(10, ("Adding cache entry with key=[%s] and timeout="
 	           "[%s] (%d seconds %s)\n", keystr,
@@ -784,7 +784,7 @@ bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
 bool gencache_set(const char *keystr, const char *value, time_t timeout)
 {
 	DATA_BLOB blob = data_blob_const(value, strlen(value)+1);
-	return gencache_set_data_blob(keystr, &blob, timeout);
+	return gencache_set_data_blob(keystr, blob, timeout);
 }
 
 struct gencache_iterate_blobs_state {
diff --git a/source3/lib/gencache.h b/source3/lib/gencache.h
index 4371835..fa72a4a 100644
--- a/source3/lib/gencache.h
+++ b/source3/lib/gencache.h
@@ -40,7 +40,7 @@ bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
 			    DATA_BLOB *blob,
 			    time_t *timeout, bool *was_expired);
 bool gencache_stabilize(void);
-bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
+bool gencache_set_data_blob(const char *keystr, DATA_BLOB blob,
 			    time_t timeout);
 void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
 				       time_t timeout, void *private_data),
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 92fc312..ce0cc89 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -154,7 +154,7 @@ static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx,
 					const char *domain_name,
-					const DATA_BLOB *blob)
+					DATA_BLOB blob)
 {
 	time_t expire_time;
 	char *key;
@@ -200,7 +200,8 @@ static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
 	}
 
 	if (r->domain_name) {
-		status = dsgetdcname_cache_store(mem_ctx, r->domain_name, &blob);
+		status = dsgetdcname_cache_store(mem_ctx, r->domain_name,
+						 blob);
 		if (!NT_STATUS_IS_OK(status)) {
 			goto done;
 		}
@@ -209,7 +210,7 @@ static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
 		}
 	}
 	if (r->dns_domain) {
-		status = dsgetdcname_cache_store(mem_ctx, r->dns_domain, &blob);
+		status = dsgetdcname_cache_store(mem_ctx, r->dns_domain, blob);
 		if (!NT_STATUS_IS_OK(status)) {
 			goto done;
 		}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 481154f..95b98bd 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -10033,7 +10033,7 @@ static bool run_local_gencache(int dummy)
 	blob = data_blob_string_const_null("bar");
 	tm = time(NULL) + 60;
 
-	if (!gencache_set_data_blob("foo", &blob, tm)) {
+	if (!gencache_set_data_blob("foo", blob, tm)) {
 		d_printf("%s: gencache_set_data_blob() failed\n", __location__);
 		return False;
 	}
@@ -10072,7 +10072,7 @@ static bool run_local_gencache(int dummy)
 	blob.data = (uint8_t *)&v;
 	blob.length = sizeof(v);
 
-	if (!gencache_set_data_blob("blob", &blob, tm)) {
+	if (!gencache_set_data_blob("blob", blob, tm)) {
 		d_printf("%s: gencache_set_data_blob() failed\n",
 			 __location__);
 		return false;
diff --git a/source3/winbindd/wb_dsgetdcname.c b/source3/winbindd/wb_dsgetdcname.c
index 125e98a..8bd7419 100644
--- a/source3/winbindd/wb_dsgetdcname.c
+++ b/source3/winbindd/wb_dsgetdcname.c
@@ -153,7 +153,7 @@ NTSTATUS wb_dsgetdcname_gencache_set(const char *domname,
 		return status;
 	}
 
-	ok = gencache_set_data_blob(key, &blob, time(NULL)+3600);
+	ok = gencache_set_data_blob(key, blob, time(NULL)+3600);
 
 	if (!ok) {
 		DBG_WARNING("gencache_set_data_blob for key %s failed\n", key);
-- 
1.9.1


From 94e64df81828063bb7973b251a59b129273fa8b9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 Aug 2017 18:11:49 +0200
Subject: [PATCH 05/10] lib: Add namemap_cache

A few functions to maintain lookupname and lookupsid cache in gencache.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/namemap_cache.c | 323 ++++++++++++++++++++++++++++++++++++++++++++
 source3/lib/namemap_cache.h |  45 ++++++
 source3/wscript_build       |   1 +
 3 files changed, 369 insertions(+)
 create mode 100644 source3/lib/namemap_cache.c
 create mode 100644 source3/lib/namemap_cache.h

diff --git a/source3/lib/namemap_cache.c b/source3/lib/namemap_cache.c
new file mode 100644
index 0000000..62252b2
--- /dev/null
+++ b/source3/lib/namemap_cache.c
@@ -0,0 +1,323 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utils for caching sid2name and name2sid
+ * Copyright (C) Volker Lendecke 2017
+ *
+ * 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 "replace.h"
+#include "namemap_cache.h"
+#include "source3/lib/gencache.h"
+#include "lib/util/debug.h"
+#include "lib/util/strv.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/charset/charset.h"
+#include "libcli/security/dom_sid.h"
+
+bool namemap_cache_set_sid2name(const struct dom_sid *sid,
+				const char *domain, const char *name,
+				enum lsa_SidType type, time_t timeout)
+{
+	char typebuf[16];
+	char sidbuf[DOM_SID_STR_BUFLEN];
+	char keybuf[DOM_SID_STR_BUFLEN+10];
+	char *val = NULL;
+	int ret;
+	bool ok = false;
+
+	if ((sid == NULL) || is_null_sid(sid)) {
+		return true;
+	}
+	if (domain == NULL) {
+		domain = "";
+	}
+	if (name == NULL) {
+		name = "";
+	}
+	if (type == SID_NAME_UNKNOWN) {
+		domain = "";
+		name = "";
+	}
+
+	snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
+	snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf);
+
+	ret = strv_add(talloc_tos(), &val, domain);
+	if (ret != 0) {
+		DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
+		goto fail;
+	}
+	ret = strv_add(NULL, &val, name);
+	if (ret != 0) {
+		DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
+		goto fail;
+	}
+	ret = strv_add(NULL, &val, typebuf);
+	if (ret != 0) {
+		DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
+		goto fail;
+	}
+
+	dom_sid_string_buf(sid, sidbuf, sizeof(sidbuf));
+	snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf);
+
+	ok = gencache_set_data_blob(
+		keybuf, (DATA_BLOB) { .data = (uint8_t *)val,
+				      .length = talloc_get_size(val) },
+		timeout);
+	if (!ok) {
+		DBG_DEBUG("gencache_set_data_blob failed\n");
+	}
+fail:
+	TALLOC_FREE(val);
+	return ok;
+}
+
+struct namemap_cache_find_sid_state {
+	void (*fn)(const char *domain, const char *name,
+		   enum lsa_SidType type, time_t timeout,
+		   void *private_data);
+	void *private_data;
+	bool ok;
+};
+
+static void namemap_cache_find_sid_parser(time_t timeout, DATA_BLOB blob,
+					  void *private_data)
+{
+	struct namemap_cache_find_sid_state *state = private_data;
+	const char *strv = (const char *)blob.data;
+	size_t strv_len = blob.length;
+	const char *domain;
+	const char *name;
+	const char *typebuf;
+	char *endptr;
+	unsigned long type;
+
+	state->ok = false;
+
+	domain = strv_len_next(strv, strv_len, NULL);
+	if (domain == NULL) {
+		return;
+	}
+	name = strv_len_next(strv, strv_len, domain);
+	if (name == NULL) {
+		return;
+	}
+	typebuf = strv_len_next(strv, strv_len, name);
+	if (typebuf == NULL) {
+		return;
+	}
+
+	type = strtoul(typebuf, &endptr, 10);
+	if (*endptr != '\0') {
+		return;
+	}
+	if ((type == ULONG_MAX) && (errno == ERANGE)) {
+		return;
+	}
+
+	state->fn(domain, name, (enum lsa_SidType)type, timeout,
+		  state->private_data);
+
+	state->ok = true;
+}
+
+bool namemap_cache_find_sid(const struct dom_sid *sid,
+			    void (*fn)(const char *domain, const char *name,
+				       enum lsa_SidType type, time_t timeout,
+				       void *private_data),
+			    void *private_data)
+{
+	struct namemap_cache_find_sid_state state = {
+		.fn = fn, .private_data = private_data
+	};
+	char sidbuf[DOM_SID_STR_BUFLEN];
+	char keybuf[DOM_SID_STR_BUFLEN+10];
+	bool ok;
+
+	dom_sid_string_buf(sid, sidbuf, sizeof(sidbuf));
+	snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf);
+
+	ok = gencache_parse(keybuf, namemap_cache_find_sid_parser, &state);
+	if (!ok) {
+		DBG_DEBUG("gencache_parse(%s) failed\n", keybuf);
+		return false;
+	}
+
+	if (!state.ok) {
+		DBG_DEBUG("Could not parse %s, deleting\n", keybuf);
+		gencache_del(keybuf);
+		return false;
+	}
+
+	return true;
+}
+
+bool namemap_cache_set_name2sid(const char *domain, const char *name,
+				const struct dom_sid *sid,
+				enum lsa_SidType type,
+				time_t timeout)
+{
+	char typebuf[16];
+	char sidbuf[DOM_SID_STR_BUFLEN];
+	char *key;
+	char *key_upper;
+	char *val = NULL;
+	int ret;
+	bool ok = false;
+
+	if (domain == NULL) {
+		domain = "";
+	}
+	if (name == NULL) {
+		name = "";
+	}
+	if (type == SID_NAME_UNKNOWN) {
+		sidbuf[0] = '\0';
+	} else {
+		dom_sid_string_buf(sid, sidbuf, sizeof(sidbuf));
+	}
+
+	snprintf(typebuf, sizeof(typebuf), "%d", (int)type);
+
+	key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
+	if (key == NULL) {
+		DBG_DEBUG("talloc_asprintf failed\n");
+		goto fail;
+	}
+	key_upper = strupper_talloc(key, key);
+	if (key_upper == NULL) {
+		DBG_DEBUG("strupper_talloc failed\n");
+		goto fail;
+	}
+
+	ret = strv_add(key, &val, sidbuf);
+	if (ret != 0) {
+		DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
+		goto fail;
+	}
+	ret = strv_add(NULL, &val, typebuf);
+	if (ret != 0) {
+		DBG_DEBUG("strv_add failed: %s\n", strerror(ret));
+		goto fail;
+	}
+
+	ok = gencache_set_data_blob(
+		key_upper, (DATA_BLOB) { .data = (uint8_t *)val,
+					 .length = talloc_get_size(val) },
+		timeout);
+	if (!ok) {
+		DBG_DEBUG("gencache_set_data_blob failed\n");
+	}
+fail:
+	TALLOC_FREE(key);
+	return ok;
+}
+
+struct namemap_cache_find_name_state {
+	void (*fn)(const struct dom_sid *sid,
+		   enum lsa_SidType type, time_t timeout,
+		   void *private_data);
+	void *private_data;
+	bool ok;
+};
+
+static void namemap_cache_find_name_parser(time_t timeout, DATA_BLOB blob,
+					   void *private_data)
+{
+	struct namemap_cache_find_name_state *state = private_data;
+	const char *strv = (const char *)blob.data;
+	size_t strv_len = blob.length;
+	const char *sidbuf;
+	const char *sid_endptr;
+	const char *typebuf;
+	char *endptr;
+	struct dom_sid sid;
+	unsigned long type;
+	bool ok;
+
+	state->ok = false;
+
+	sidbuf = strv_len_next(strv, strv_len, NULL);
+	if (sidbuf == NULL) {
+		return;
+	}
+	typebuf = strv_len_next(strv, strv_len, sidbuf);
+	if (typebuf == NULL) {
+		return;
+	}
+
+	ok = dom_sid_parse_endp(sidbuf, &sid, &sid_endptr);
+	if (!ok) {
+		return;
+	}
+	if (*sid_endptr != '\0') {
+		return;
+	}
+
+	type = strtoul(typebuf, &endptr, 10);
+	if (*endptr != '\0') {
+		return;
+	}
+	if ((type == ULONG_MAX) && (errno == ERANGE)) {
+		return;
+	}
+
+	state->fn(&sid, (enum lsa_SidType)type, timeout, state->private_data);
+
+	state->ok = true;
+}
+
+bool namemap_cache_find_name(const char *domain, const char *name,
+			     void (*fn)(const struct dom_sid *sid,
+					enum lsa_SidType type, time_t timeout,
+					void *private_data),
+			     void *private_data)
+{
+	struct namemap_cache_find_name_state state = {
+		.fn = fn, .private_data = private_data
+	};
+	char *key;
+	char *key_upper;
+	bool ret = false;
+	bool ok;
+
+	key = talloc_asprintf(talloc_tos(), "NAME2SID/%s\\%s", domain, name);
+	if (key == NULL) {
+		DBG_DEBUG("talloc_asprintf failed\n");
+		return false;
+	}
+	key_upper = strupper_talloc(key, key);
+	if (key_upper == NULL) {
+		DBG_DEBUG("strupper_talloc failed\n");
+		goto fail;
+	}
+
+	ok = gencache_parse(key_upper, namemap_cache_find_name_parser, &state);
+	if (!ok) {
+		DBG_DEBUG("gencache_parse(%s) failed\n", key_upper);
+		goto fail;
+	}
+
+	if (!state.ok) {
+		DBG_DEBUG("Could not parse %s, deleting\n", key_upper);
+		goto fail;
+	}
+
+	ret = true;
+fail:
+	TALLOC_FREE(key);
+	return ret;
+}
diff --git a/source3/lib/namemap_cache.h b/source3/lib/namemap_cache.h
new file mode 100644
index 0000000..a70de34
--- /dev/null
+++ b/source3/lib/namemap_cache.h
@@ -0,0 +1,45 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utils for caching sid2name and name2sid
+ * Copyright (C) Volker Lendecke 2017
+ *
+ * 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/>.
+ */
+
+#ifndef __LIB_NAMEMAP_CACHE_H__
+#define __LIB_NAMEMAP_CACHE_H__
+
+#include "lib/util/time.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/lsa.h"
+
+bool namemap_cache_set_sid2name(const struct dom_sid *sid,
+				const char *domain, const char *name,
+				enum lsa_SidType type, time_t timeout);
+bool namemap_cache_set_name2sid(const char *domain, const char *name,
+				const struct dom_sid *sid,
+				enum lsa_SidType type,
+				time_t timeout);
+bool namemap_cache_find_sid(const struct dom_sid *sid,
+			    void (*fn)(const char *domain, const char *name,
+				       enum lsa_SidType type, time_t timeout,
+				       void *private_data),
+			    void *private_data);
+bool namemap_cache_find_name(const char *domain, const char *name,
+			     void (*fn)(const struct dom_sid *sid,
+					enum lsa_SidType type, time_t timeout,
+					void *private_data),
+			     void *private_data);
+
+#endif
diff --git a/source3/wscript_build b/source3/wscript_build
index f13429d..83b99cc 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -389,6 +389,7 @@ bld.SAMBA3_SUBSYSTEM('samba3core',
                           lib/audit.c
                           lib/tevent_wait.c
                           lib/idmap_cache.c
+                          lib/namemap_cache.c
                           lib/util_ea.c
                           lib/background.c
                           ''',
-- 
1.9.1


From 168667481d5c719838f1aec2633f01202ba62e67 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 3 Aug 2017 16:26:04 +0200
Subject: [PATCH 06/10] net: Parse namemap_cache in "net cache list"

namemap_cache.c saves these as strv lists: An array of 0-terminated strings.
"net cache list" only printfs the values, so they would be cut off.

We might want to do this with other gencache values too in the future.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/utils/net_cache.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/source3/utils/net_cache.c b/source3/utils/net_cache.c
index f43eb0e..8f9f69f 100644
--- a/source3/utils/net_cache.c
+++ b/source3/utils/net_cache.c
@@ -23,6 +23,7 @@
 #include "../librpc/gen_ndr/netlogon.h"
 #include "../librpc/gen_ndr/ndr_netlogon.h"
 #include "libcli/security/dom_sid.h"
+#include "lib/util/strv.h"
 
 /**
  * @file net_cache.c
@@ -77,6 +78,24 @@ static void print_cache_entry(const char* keystr, DATA_BLOB value,
 
 	datastr = (char *)value.data;
 
+	if (strnequal(keystr, "NAME2SID/", strlen("NAME2SID/"))) {
+		const char *strv = (char *)value.data;
+		size_t strv_len = value.length;
+		const char *sid = strv_len_next(strv, strv_len, NULL);
+		const char *type = strv_len_next(strv, strv_len, sid);
+		datastr = talloc_asprintf(talloc_tos(), "%s (%s)", sid, type);
+	}
+
+	if (strnequal(keystr, "SID2NAME/", strlen("SID2NAME/"))) {
+		const char *strv = (char *)value.data;
+		size_t strv_len = value.length;
+		const char *domain = strv_len_next(strv, strv_len, NULL);
+		const char *name = strv_len_next(strv, strv_len, domain);
+		const char *type = strv_len_next(strv, strv_len, name);
+		datastr = talloc_asprintf(talloc_tos(), "%s\\%s (%s)",
+					  domain, name, type);
+	}
+
 	if ((value.length > 0) && (value.data[value.length-1] != '\0')) {
 		datastr_free = talloc_asprintf(
 			talloc_tos(), "<binary length %d>",
-- 
1.9.1


From 11b98979e6892d10bff9cf5a346104dd1635ff2c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 3 Aug 2017 16:26:25 +0200
Subject: [PATCH 07/10] torture3: Test namemap_cache

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/selftest/tests.py            |   1 +
 source3/torture/proto.h              |   1 +
 source3/torture/test_namemap_cache.c | 262 +++++++++++++++++++++++++++++++++++
 source3/torture/torture.c            |   1 +
 source3/wscript_build                |   1 +
 5 files changed, 266 insertions(+)
 create mode 100644 source3/torture/test_namemap_cache.c

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 3e5cffd..e391355 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -154,6 +154,7 @@ local_tests = [
     "LOCAL-G-LOCK3",
     "LOCAL-G-LOCK4",
     "LOCAL-G-LOCK5",
+    "LOCAL-NAMEMAP-CACHE1",
     "LOCAL-hex_encode_buf",
     "LOCAL-remove_duplicate_addrs2"]
 
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 8a032da..83e0c74 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -132,5 +132,6 @@ bool run_g_lock3(int dummy);
 bool run_g_lock4(int dummy);
 bool run_g_lock5(int dummy);
 bool run_g_lock_ping_pong(int dummy);
+bool run_local_namemap_cache1(int dummy);
 
 #endif /* __TORTURE_H__ */
diff --git a/source3/torture/test_namemap_cache.c b/source3/torture/test_namemap_cache.c
new file mode 100644
index 0000000..07c6bf4
--- /dev/null
+++ b/source3/torture/test_namemap_cache.c
@@ -0,0 +1,262 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * namemap_cache.c
+ * Copyright (C) Volker Lendecke 2017
+ *
+ * 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 "torture/proto.h"
+#include "lib/namemap_cache.h"
+#include "libcli/security/dom_sid.h"
+
+static const struct dom_sid domsid = {
+	1, 4, {0,0,0,0,0,5}, {21, 123, 456, 789}
+};
+
+static void namemap_cache1_fn1(const char *domain, const char *name,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = strequal(domain, "nt authority");
+	ok &= strequal(name, "network");
+	ok &= (type == SID_NAME_WKN_GRP);
+
+	*p_ok = ok;
+}
+
+static void namemap_cache1_fn2(const struct dom_sid *sid,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = dom_sid_equal(sid, &global_sid_Network);
+	ok &= (type == SID_NAME_WKN_GRP);
+
+	*p_ok = ok;
+}
+
+static void namemap_cache1_fn3(const char *domain, const char *name,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = strequal(domain, "");
+	ok &= strequal(name, "everyone");
+	ok &= (type == SID_NAME_WKN_GRP);
+
+	*p_ok = ok;
+}
+
+static void namemap_cache1_fn4(const struct dom_sid *sid,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = dom_sid_equal(sid, &global_sid_World);
+	ok &= (type == SID_NAME_WKN_GRP);
+
+	*p_ok = ok;
+}
+
+static void namemap_cache1_fn5(const char *domain, const char *name,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = strequal(domain, "samba-dom");
+	ok &= strequal(name, "");
+	ok &= (type == SID_NAME_DOMAIN);
+
+	*p_ok = ok;
+}
+
+static void namemap_cache1_fn6(const struct dom_sid *sid,
+			       enum lsa_SidType type, time_t timeout,
+			       void *private_data)
+{
+	bool *p_ok = private_data;
+	bool ok;
+
+	ok = dom_sid_equal(sid, &domsid);
+	ok &= (type == SID_NAME_DOMAIN);
+
+	*p_ok = ok;
+}
+
+bool run_local_namemap_cache1(int dummy)
+{
+	bool found;
+	bool ok;
+
+	ok = gencache_set("SID2NAME/S-1-5-2", "invalid", time(NULL)+60);
+	if (!ok) {
+		fprintf(stderr, "gencache_set failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_sid(&global_sid_Network, namemap_cache1_fn1,
+				    &found);
+	if (ok) {
+		fprintf(stderr, "namemap_cache_find_sid parsed valid value\n");
+		return false;
+	}
+
+	ok = namemap_cache_set_sid2name(&global_sid_Network,
+					"NT Authority", "Network",
+					SID_NAME_WKN_GRP,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set_sid2name failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_sid(&global_sid_Network, namemap_cache1_fn1,
+				    &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_sid failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	ok = namemap_cache_set_name2sid("NT Authority", "Network",
+					&global_sid_Network,
+					SID_NAME_WKN_GRP,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set_name2sid failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_name("nt authority", "network",
+				     namemap_cache1_fn2, &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_name failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_name("foo", "bar", namemap_cache1_fn2, &found);
+	if (ok) {
+		fprintf(stderr,
+			"namemap_cache_find_name succeeded unexpectedly\n");
+		return false;
+	}
+
+	/*
+	 * Test "" domain name
+	 */
+
+	ok = namemap_cache_set_sid2name(&global_sid_World, "", "Everyone",
+					SID_NAME_WKN_GRP,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set_sid2name failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_sid(&global_sid_World, namemap_cache1_fn3,
+				    &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_sid failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	ok = namemap_cache_set_name2sid("", "Everyone",
+					&global_sid_World, SID_NAME_WKN_GRP,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_name("", "everyone",
+				     namemap_cache1_fn4, &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_name failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	/*
+	 * Test domain only
+	 */
+
+	ok = namemap_cache_set_sid2name(&domsid, "SAMBA-DOM", "",
+					SID_NAME_DOMAIN,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_sid(&domsid, namemap_cache1_fn5,
+				    &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_sid failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	ok = namemap_cache_set_name2sid("SAMBA-DOM", "",
+					&domsid, SID_NAME_DOMAIN,
+					time(NULL) + 60);
+	if (!ok) {
+		fprintf(stderr, "namemap_cache_set failed\n");
+		return false;
+	}
+
+	ok = namemap_cache_find_name("samba-dom", "",
+				     namemap_cache1_fn6, &found);
+	if (!ok) {
+		fprintf(stderr, "namecache_find_name failed\n");
+		return false;
+	}
+	if (!found) {
+		fprintf(stderr, "wrong values found\n");
+		return false;
+	}
+
+	gencache_stabilize();
+
+	return true;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 95b98bd..c39b09a 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11585,6 +11585,7 @@ static struct {
 	{ "LOCAL-G-LOCK5", run_g_lock5, 0 },
 	{ "LOCAL-G-LOCK-PING-PONG", run_g_lock_ping_pong, 0 },
 	{ "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 },
+	{ "LOCAL-NAMEMAP-CACHE1", run_local_namemap_cache1, 0 },
 	{ "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 },
 	{NULL, NULL, 0}};
 
diff --git a/source3/wscript_build b/source3/wscript_build
index 83b99cc..8b46cae 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1174,6 +1174,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
                         torture/bench_pthreadpool.c
                         torture/wbc_async.c
                         torture/test_g_lock.c
+                        torture/test_namemap_cache.c
                         ''',
                  deps='''
                       talloc
-- 
1.9.1


From 67893062d88edb93c24d86a515a6ef22436eb6f8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 6 Aug 2017 18:11:02 +0200
Subject: [PATCH 08/10] winbindd: Factor out winbindd_domain_init_backend from
 get_cache()

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_cache.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index fbf4451..76b79a3 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -121,12 +121,11 @@ static char *wcache_path(void)
 	return state_path("winbindd_cache.tdb");
 }
 
-/* get the winbind_cache structure */
-static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+static void winbindd_domain_init_backend(struct winbindd_domain *domain)
 {
-	struct winbind_cache *ret = wcache;
-
-	/* We have to know what type of domain we are dealing with first. */
+	if (domain->backend != NULL) {
+		return;
+	}
 
 	if (domain->internal) {
 		domain->backend = &builtin_passdb_methods;
@@ -173,6 +172,14 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
 		DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
 		domain->backend = &reconnect_methods;
 	}
+}
+
+/* get the winbind_cache structure */
+static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+{
+	struct winbind_cache *ret = wcache;
+
+	winbindd_domain_init_backend(domain);
 
 	if (ret != NULL) {
 		return ret;
-- 
1.9.1


From bb76c0cbe0d53aee137c3b6a7b962216c3c32468 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 6 Aug 2017 18:13:10 +0200
Subject: [PATCH 09/10] winbindd: Move name<->sid cache to gencache

The mapping from name to sid and vice versa has nothing to
do with a specific domain. It is publically available. Thus put
it into gencache without referring to the domain this was
retrieved from

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_cache.c | 325 ++++++++++++++++----------------------
 1 file changed, 139 insertions(+), 186 deletions(-)

diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 76b79a3..9ffb328 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -35,6 +35,7 @@
 #include "passdb/machine_sid.h"
 #include "util_tdb.h"
 #include "libsmb/samlogon_cache.h"
+#include "lib/namemap_cache.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -945,59 +946,40 @@ static void wcache_save_name_to_sid(struct winbindd_domain *domain,
 				    const char *name, const struct dom_sid *sid,
 				    enum lsa_SidType type)
 {
-	struct cache_entry *centry;
-	fstring uname;
-
-	centry = centry_start(domain, status);
-	if (!centry)
-		return;
+	bool ok;
 
-	if ((domain_name == NULL) || (domain_name[0] == '\0')) {
-		struct winbindd_domain *mydomain =
-			find_domain_from_sid_noinit(sid);
-		if (mydomain != NULL) {
-			domain_name = mydomain->name;
-		}
+	ok = namemap_cache_set_name2sid(domain_name, name, sid, type,
+					time(NULL) + lp_winbind_cache_time());
+	if (!ok) {
+		DBG_DEBUG("namemap_cache_set_name2sid failed\n");
 	}
 
-	centry_put_uint32(centry, type);
-	centry_put_sid(centry, sid);
-	fstrcpy(uname, name);
-	(void)strupper_m(uname);
-	centry_end(centry, "NS/%s/%s", domain_name, uname);
-	DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
-		  uname, sid_string_dbg(sid), nt_errstr(status)));
-	centry_free(centry);
+	/*
+	 * Don't store the reverse mapping. The name came from user
+	 * input, and we might not have the correct capitalization,
+	 * which is important for nsswitch.
+	 */
 }
 
 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 
 				    const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
 {
-	struct cache_entry *centry;
-	fstring sid_string;
-
-	centry = centry_start(domain, status);
-	if (!centry)
-		return;
+	bool ok;
 
-	if ((domain_name == NULL) || (domain_name[0] == '\0')) {
-		struct winbindd_domain *mydomain =
-			find_domain_from_sid_noinit(sid);
-		if (mydomain != NULL) {
-			domain_name = mydomain->name;
-		}
+	ok = namemap_cache_set_sid2name(sid, domain_name, name, type,
+					time(NULL) + lp_winbind_cache_time());
+	if (!ok) {
+		DBG_DEBUG("namemap_cache_set_sid2name failed\n");
 	}
 
-	if (NT_STATUS_IS_OK(status)) {
-		centry_put_uint32(centry, type);
-		centry_put_string(centry, domain_name);
-		centry_put_string(centry, name);
+	if (type != SID_NAME_UNKNOWN) {
+		ok = namemap_cache_set_name2sid(
+			domain_name, name, sid, type,
+			time(NULL) + lp_winbind_cache_time());
+		if (!ok) {
+			DBG_DEBUG("namemap_cache_set_name2sid failed\n");
+		}
 	}
-
-	centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
-	DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
-		  domain_name, name, nt_errstr(status)));
-	centry_free(centry);
 }
 
 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
@@ -1752,47 +1734,51 @@ skip_save:
 	return status;
 }
 
+struct wcache_name_to_sid_state {
+	struct dom_sid *sid;
+	enum lsa_SidType *type;
+	bool offline;
+	bool found;
+};
+
+static void wcache_name_to_sid_fn(const struct dom_sid *sid,
+				  enum lsa_SidType type, time_t timeout,
+				  void *private_data)
+{
+	struct wcache_name_to_sid_state *state = private_data;
+
+	*state->sid = *sid;
+	*state->type = type;
+	state->found = (state->offline || (timeout < time(NULL)));
+}
+
 static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
 				   const char *domain_name,
 				   const char *name,
 				   struct dom_sid *sid,
 				   enum lsa_SidType *type)
 {
-	struct winbind_cache *cache = get_cache(domain);
-	struct cache_entry *centry;
-	NTSTATUS status;
-	char *uname;
+	struct wcache_name_to_sid_state state = {
+		.sid = sid, .type = type, .found = false,
+		.offline = is_domain_offline(domain),
+	};
+	bool ok;
 
-	if (cache->tdb == NULL) {
+	ok = namemap_cache_find_name(domain_name, name, wcache_name_to_sid_fn,
+				     &state);
+	if (!ok) {
+		DBG_DEBUG("namemap_cache_find_name failed\n");
 		return NT_STATUS_NOT_FOUND;
 	}
-
-	uname = talloc_strdup_upper(talloc_tos(), name);
-	if (uname == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	if ((domain_name == NULL) || (domain_name[0] == '\0')) {
-		domain_name = domain->name;
-	}
-
-	centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
-	TALLOC_FREE(uname);
-	if (centry == NULL) {
+	if (!state.found) {
+		DBG_DEBUG("cache entry not found\n");
 		return NT_STATUS_NOT_FOUND;
 	}
-
-	status = centry->status;
-	if (NT_STATUS_IS_OK(status)) {
-		*type = (enum lsa_SidType)centry_uint32(centry);
-		centry_sid(centry, sid);
+	if (*type == SID_NAME_UNKNOWN) {
+		return NT_STATUS_NONE_MAPPED;
 	}
 
-	DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
-		  "%s\n", domain->name, nt_errstr(status) ));
-
-	centry_free(centry);
-	return status;
+	return NT_STATUS_OK;
 }
 
 /* convert a single name to a sid in a domain */
@@ -1830,6 +1816,7 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 	DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
 		domain->name ));
 
+	winbindd_domain_init_backend(domain);
 	status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
 					      name, flags, sid, type);
 
@@ -1851,7 +1838,14 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 
 	if (domain->online &&
 	    (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
-		wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
+		enum lsa_SidType save_type = *type;
+
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+			save_type = SID_NAME_UNKNOWN;
+		}
+
+		wcache_save_name_to_sid(domain, status, domain_name, name, sid,
+					save_type);
 
 		/* Only save the reverse mapping if this was not a UPN */
 		if (!strchr(name, '@')) {
@@ -1859,13 +1853,41 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 				return NT_STATUS_INVALID_PARAMETER;
 			}
 			(void)strlower_m(discard_const_p(char, name));
-			wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
+			wcache_save_sid_to_name(domain, status, sid,
+						domain_name, name, save_type);
 		}
 	}
 
 	return status;
 }
 
+struct wcache_sid_to_name_state {
+	TALLOC_CTX *mem_ctx;
+	char **domain_name;
+	char **name;
+	enum lsa_SidType *type;
+	bool offline;
+	bool found;
+};
+
+static void wcache_sid_to_name_fn(const char *domain, const char *name,
+				  enum lsa_SidType type, time_t timeout,
+				  void *private_data)
+{
+	struct wcache_sid_to_name_state *state = private_data;
+
+	*state->domain_name = talloc_strdup(state->mem_ctx, domain);
+	if (*state->domain_name == NULL) {
+		return;
+	}
+	*state->name = talloc_strdup(state->mem_ctx, name);
+	if (*state->name == NULL) {
+		return;
+	}
+	*state->type = type;
+	state->found = (state->offline || (timeout < time(NULL)));
+}
+
 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
 				   const struct dom_sid *sid,
 				   TALLOC_CTX *mem_ctx,
@@ -1873,39 +1895,27 @@ static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
 				   char **name,
 				   enum lsa_SidType *type)
 {
-	struct winbind_cache *cache = get_cache(domain);
-	struct cache_entry *centry;
-	char *sid_string;
-	NTSTATUS status;
+	struct wcache_sid_to_name_state state = {
+		.mem_ctx = mem_ctx, .found = false,
+		.domain_name = domain_name, .name = name, .type = type,
+		.offline = is_domain_offline(domain)
+	};
+	bool ok;
 
-	if (cache->tdb == NULL) {
+	ok = namemap_cache_find_sid(sid, wcache_sid_to_name_fn, &state);
+	if (!ok) {
+		DBG_DEBUG("namemap_cache_find_name failed\n");
 		return NT_STATUS_NOT_FOUND;
 	}
-
-	sid_string = sid_string_tos(sid);
-	if (sid_string == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
-	TALLOC_FREE(sid_string);
-	if (centry == NULL) {
+	if (!state.found) {
+		DBG_DEBUG("cache entry not found\n");
 		return NT_STATUS_NOT_FOUND;
 	}
-
-	if (NT_STATUS_IS_OK(centry->status)) {
-		*type = (enum lsa_SidType)centry_uint32(centry);
-		*domain_name = centry_string(centry, mem_ctx);
-		*name = centry_string(centry, mem_ctx);
+	if (*type == SID_NAME_UNKNOWN) {
+		return NT_STATUS_NONE_MAPPED;
 	}
 
-	status = centry->status;
-	centry_free(centry);
-
-	DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
-		  "%s\n", domain->name, nt_errstr(status) ));
-
-	return status;
+	return NT_STATUS_OK;
 }
 
 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
@@ -1944,6 +1954,8 @@ NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
 	DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
 		domain->name ));
 
+	winbindd_domain_init_backend(domain);
+
 	status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
@@ -2014,49 +2026,45 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
 
 	for (i=0; i<num_rids; i++) {
 		struct dom_sid sid;
-		struct cache_entry *centry;
-		fstring tmp;
+		NTSTATUS status;
+		enum lsa_SidType type;
+		char *dom, *name;
 
 		if (!sid_compose(&sid, domain_sid, rids[i])) {
 			result = NT_STATUS_INTERNAL_ERROR;
 			goto error;
 		}
 
-		centry = wcache_fetch(cache, domain, "SN/%s",
-				      sid_to_fstring(tmp, &sid));
-		if (!centry) {
-			goto do_query;
-		}
+		status = wcache_sid_to_name(domain, &sid, *names, &dom,
+					    &name, &type);
 
 		(*types)[i] = SID_NAME_UNKNOWN;
 		(*names)[i] = talloc_strdup(*names, "");
 
-		if (NT_STATUS_IS_OK(centry->status)) {
-			char *dom;
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+			/* not cached */
+			goto do_query;
+		}
+
+		if (NT_STATUS_IS_OK(status)) {
 			have_mapped = true;
-			(*types)[i] = (enum lsa_SidType)centry_uint32(centry);
+			(*types)[i] = type;
 
-			dom = centry_string(centry, mem_ctx);
 			if (*domain_name == NULL) {
 				*domain_name = dom;
 			} else {
-				talloc_free(dom);
+				TALLOC_FREE(dom);
 			}
 
-			(*names)[i] = centry_string(centry, *names);
+			(*names)[i] = name;
 
-		} else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
-			   || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
+		} else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
 			have_unmapped = true;
-
 		} else {
 			/* something's definitely wrong */
-			result = centry->status;
-			centry_free(centry);
+			result = status;
 			goto error;
 		}
-
-		centry_free(centry);
 	}
 
 	if (!have_mapped) {
@@ -2102,50 +2110,43 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
 
 			for (i=0; i<num_rids; i++) {
 				struct dom_sid sid;
-				struct cache_entry *centry;
-				fstring tmp;
+				NTSTATUS status;
+				enum lsa_SidType type;
+				char *dom, *name;
 
 				if (!sid_compose(&sid, domain_sid, rids[i])) {
 					result = NT_STATUS_INTERNAL_ERROR;
 					goto error;
 				}
 
-				centry = wcache_fetch(cache, domain, "SN/%s",
-						      sid_to_fstring(tmp, &sid));
-				if (!centry) {
-					(*types)[i] = SID_NAME_UNKNOWN;
-					(*names)[i] = talloc_strdup(*names, "");
-					continue;
-				}
+				status = wcache_sid_to_name(domain, &sid,
+							    *names, &dom,
+							    &name, &type);
 
 				(*types)[i] = SID_NAME_UNKNOWN;
 				(*names)[i] = talloc_strdup(*names, "");
 
-				if (NT_STATUS_IS_OK(centry->status)) {
-					char *dom;
+				if (NT_STATUS_IS_OK(status)) {
 					have_mapped = true;
-					(*types)[i] = (enum lsa_SidType)centry_uint32(centry);
+					(*types)[i] = type;
 
-					dom = centry_string(centry, mem_ctx);
 					if (*domain_name == NULL) {
 						*domain_name = dom;
 					} else {
-						talloc_free(dom);
+						TALLOC_FREE(dom);
 					}
 
-					(*names)[i] = centry_string(centry, *names);
+					(*names)[i] = name;
 
-				} else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+				} else if (NT_STATUS_EQUAL(
+						   status,
+						   NT_STATUS_NONE_MAPPED)) {
 					have_unmapped = true;
-
 				} else {
 					/* something's definitely wrong */
-					result = centry->status;
-					centry_free(centry);
+					result = status;
 					goto error;
 				}
-
-				centry_free(centry);
 			}
 
 			if (!have_mapped) {
@@ -3604,52 +3605,6 @@ static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbu
 	return 0;
 }
 
-static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
-		       struct tdb_validation_status *state)
-{
-	struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-	if (!centry) {
-		return 1;
-	}
-
-	(void)centry_uint32(centry);
-	if (NT_STATUS_IS_OK(centry->status)) {
-		struct dom_sid sid;
-		(void)centry_sid(centry, &sid);
-	}
-
-	centry_free(centry);
-
-	if (!(state->success)) {
-		return 1;
-	}
-	DEBUG(10,("validate_ns: %s ok\n", keystr));
-	return 0;
-}
-
-static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
-		       struct tdb_validation_status *state)
-{
-	struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-	if (!centry) {
-		return 1;
-	}
-
-	if (NT_STATUS_IS_OK(centry->status)) {
-		(void)centry_uint32(centry);
-		(void)centry_string(centry, mem_ctx);
-		(void)centry_string(centry, mem_ctx);
-	}
-
-	centry_free(centry);
-
-	if (!(state->success)) {
-		return 1;
-	}
-	DEBUG(10,("validate_sn: %s ok\n", keystr));
-	return 0;
-}
-
 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
 		      struct tdb_validation_status *state)
 {
@@ -4024,8 +3979,6 @@ struct key_val_struct {
 	int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
 } key_val[] = {
 	{"SEQNUM/", validate_seqnum},
-	{"NS/", validate_ns},
-	{"SN/", validate_sn},
 	{"U/", validate_u},
 	{"LOC_POL/", validate_loc_pol},
 	{"PWD_POL/", validate_pwd_pol},
-- 
1.9.1


From 506b052ab62462e637a02ce10a6c70eb41a33aae Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 8 Aug 2017 14:24:27 +0200
Subject: [PATCH 10/10] winbindd: Name<->SID cache is not sequence number based
 anymore

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_cache.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 9ffb328..9f9e878 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -1834,7 +1834,6 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 		}
 	}
 	/* and save it */
-	refresh_sequence_number(domain);
 
 	if (domain->online &&
 	    (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
@@ -1973,7 +1972,6 @@ NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
 		}
 	}
 	/* and save it */
-	refresh_sequence_number(domain);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
-- 
1.9.1



More information about the samba-technical mailing list