diff options
Diffstat (limited to 'source3/lib/namemap_cache.c')
-rw-r--r-- | source3/lib/namemap_cache.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/source3/lib/namemap_cache.c b/source3/lib/namemap_cache.c new file mode 100644 index 0000000..2e8d298 --- /dev/null +++ b/source3/lib/namemap_cache.c @@ -0,0 +1,333 @@ +/* + * 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/util.h" +#include "lib/util/talloc_stack.h" +#include "lib/util/charset/charset.h" +#include "libcli/security/dom_sid.h" +#include "lib/util/smb_strtox.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]; + struct dom_sid_buf sidbuf; + char keybuf[sizeof(sidbuf.buf)+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); + + 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_str_buf(sid, &sidbuf); + snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf); + + 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, + bool expired, + void *private_data); + void *private_data; + bool ok; +}; + +static void namemap_cache_find_sid_parser( + const struct gencache_timeout *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; + int error = 0; + 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 = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV); + if (error != 0) { + return; + } + + state->fn(domain, + name, + (enum lsa_SidType)type, + gencache_timeout_expired(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, + bool expired, + void *private_data), + void *private_data) +{ + struct namemap_cache_find_sid_state state = { + .fn = fn, .private_data = private_data + }; + struct dom_sid_buf sidbuf; + char keybuf[sizeof(sidbuf.buf)+10]; + bool ok; + + dom_sid_str_buf(sid, &sidbuf); + snprintf(keybuf, sizeof(keybuf), "SID2NAME/%s", sidbuf.buf); + + 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]; + struct dom_sid_buf sidbuf = {{0}}; + 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) { + dom_sid_str_buf(sid, &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.buf); + 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, + bool expired, + void *private_data); + void *private_data; + bool ok; +}; + +static void namemap_cache_find_name_parser( + const struct gencache_timeout *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; + int error = 0; + 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 = smb_strtoul(typebuf, NULL, 10, &error, SMB_STR_FULL_STR_CONV); + if (error != 0) { + return; + } + + state->fn(&sid, + (enum lsa_SidType)type, + gencache_timeout_expired(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, + bool expired, + 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; +} |