From 313b12af3cd433fdf89fcbc995e0b947c4611199 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 2 Aug 2017 17:22:34 +0200 Subject: [PATCH 1/9] lib: Pass in "strv_len" to strv_valid_entry Preparation for a later commit BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 99ce76f54fd..864a3e5cf8b 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; -- 2.16.3 From f728bf2bb25ca68d591812abce0e48b41170fe2d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 2 Aug 2017 17:32:50 +0200 Subject: [PATCH 2/9] lib: Only call strlen if necessary in strv BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 864a3e5cf8b..328f561722b 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; -- 2.16.3 From 25c51436eebf5698ecd7d301b688520a1446eb7d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 2 Aug 2017 17:34:25 +0200 Subject: [PATCH 3/9] lib: Allow parsing a strv from a non-talloc const buf This will allow parsing a tdb record without having to talloc_memdup it BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 328f561722b..83d84d92528 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 398e8ead171..89f04023e44 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); -- 2.16.3 From c85348e40f4078228edf9c6be7f5beda40e07da8 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 2 Aug 2017 17:52:40 +0200 Subject: [PATCH 4/9] 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. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 1572825f605..83fa67c5700 100644 --- a/source3/lib/gencache.c +++ b/source3/lib/gencache.c @@ -275,7 +275,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; @@ -291,7 +291,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; } @@ -299,7 +299,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; @@ -310,12 +310,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, @@ -842,7 +842,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 4371835599d..fa72a4aa466 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 92fc312c6a4..ce0cc89899c 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 1709e94289c..3bc4f9cca45 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -10034,7 +10034,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; } @@ -10073,7 +10073,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 125e98ade74..8bd74198bcb 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); -- 2.16.3 From 0b55c5ac724ba48b2dac4c08d2fb81074b458f9f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 2 Aug 2017 18:11:49 +0200 Subject: [PATCH 5/9] lib: Add namemap_cache A few functions to maintain lookupname and lookupsid cache in gencache. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 00000000000..0d6ed32abc5 --- /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 . + */ + +#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; + DATA_BLOB data; + 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); + + data = data_blob_const(val, talloc_get_size(val)); + + ok = gencache_set_data_blob(keybuf, data, 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; + DATA_BLOB data; + 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; + } + + data = data_blob_const(val, talloc_get_size(val)); + + ok = gencache_set_data_blob(key_upper, data, 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 00000000000..a70de34b885 --- /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 . + */ + +#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 8b119a824c3..cc511c376d8 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -410,6 +410,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 lib/cleanupdb.c -- 2.16.3 From 28f3debb410268c672de7727c90d654623259a53 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 3 Aug 2017 16:26:04 +0200 Subject: [PATCH 6/9] 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. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 f43eb0e88c6..8f9f69f8659 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(), "", -- 2.16.3 From bb19cb000c985fd0adb37b169d26b39219366f98 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 6 Aug 2017 18:11:02 +0200 Subject: [PATCH 7/9] winbindd: Factor out winbindd_domain_init_backend from get_cache() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 98c69f8b231..8492f907553 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -119,12 +119,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; @@ -189,6 +188,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; -- 2.16.3 From 421f7b6d3ba244dce6685e1aa817c8a3dcd944b5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 6 Aug 2017 18:13:10 +0200 Subject: [PATCH 8/9] 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 BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- source3/winbindd/winbindd_cache.c | 333 ++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 190 deletions(-) diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 8492f907553..afc688fd5f9 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 @@ -961,59 +962,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, @@ -1769,47 +1751,51 @@ skip_save: return status; } -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 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 winbind_cache *cache = get_cache(domain); - struct cache_entry *centry; - NTSTATUS status; - char *uname; + struct wcache_name_to_sid_state *state = private_data; - if (cache->tdb == NULL) { - return NT_STATUS_NOT_FOUND; - } + *state->sid = *sid; + *state->type = type; + state->found = (state->offline || (timeout < time(NULL))); +} - uname = talloc_strdup_upper(talloc_tos(), name); - if (uname == NULL) { - return NT_STATUS_NO_MEMORY; - } +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 wcache_name_to_sid_state state = { + .sid = sid, .type = type, .found = false, + .offline = is_domain_offline(domain), + }; + bool ok; - if ((domain_name == NULL) || (domain_name[0] == '\0')) { - domain_name = domain->name; + 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; } - - 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 */ @@ -1847,6 +1833,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); @@ -1868,7 +1855,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, '@')) { @@ -1876,13 +1870,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, @@ -1890,39 +1912,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 @@ -1961,6 +1971,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) || @@ -2031,49 +2043,45 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain, for (i=0; istatus)) { - 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) { @@ -2119,50 +2127,43 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain, for (i=0; istatus)) { - 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) { @@ -3620,52 +3621,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) { @@ -4040,8 +3995,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}, -- 2.16.3 From 837678e9f2ba30e052e355b119528439b8ee7054 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 8 Aug 2017 14:24:27 +0200 Subject: [PATCH 9/9] winbindd: Name<->SID cache is not sequence number based anymore BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- 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 afc688fd5f9..a100ed77f2a 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -1851,7 +1851,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))) { @@ -1990,7 +1989,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; } -- 2.16.3