*/
#include "includes.h"
+#include "system/filesys.h"
#include "winbindd.h"
#include "tdb_validate.h"
#include "../libcli/auth/libcli_auth.h"
#include "../librpc/gen_ndr/ndr_wbint.h"
+#include "ads.h"
+#include "nss_info.h"
+#include "../libcli/security/security.h"
+#include "passdb/machine_sid.h"
+#include "util_tdb.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-#define WINBINDD_CACHE_VERSION 1
+#define WINBINDD_CACHE_VER1 1 /* initial db version */
+#define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
+
+#define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
#define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
extern struct winbindd_methods reconnect_methods;
extern struct winbindd_methods ads_methods;
#endif
extern struct winbindd_methods builtin_passdb_methods;
+extern struct winbindd_methods sam_passdb_methods;
/*
* JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
static const char *non_centry_keys[] = {
"SEQNUM/",
- "DR/",
- "DE/",
"WINBINDD_OFFLINE",
WINBINDD_CACHE_VERSION_KEYSTR,
NULL
struct cache_entry {
NTSTATUS status;
uint32 sequence_number;
+ uint64_t timeout;
uint8 *data;
uint32 len, ofs;
};
static struct winbind_cache *wcache;
-void winbindd_check_cache_size(time_t t)
-{
- static time_t last_check_time;
- struct stat st;
-
- if (last_check_time == (time_t)0)
- last_check_time = t;
-
- if (t - last_check_time < 60 && t - last_check_time > 0)
- return;
-
- if (wcache == NULL || wcache->tdb == NULL) {
- DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
- return;
- }
-
- if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
- DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
- return;
- }
-
- if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
- DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
- (unsigned long)st.st_size,
- (unsigned long)WINBINDD_MAX_CACHE_SIZE));
- wcache_flush_cache();
- }
-}
-
/* get the winbind_cache structure */
static struct winbind_cache *get_cache(struct winbindd_domain *domain)
{
domain->backend = &builtin_passdb_methods;
domain->initialized = True;
}
+
+ if (strequal(domain->name, get_global_sam_name()) &&
+ sid_check_is_our_sam(&domain->sid)) {
+ domain->backend = &sam_passdb_methods;
+ domain->initialized = True;
+ }
+
if ( !domain->initialized ) {
init_dc_connection( domain );
}
return true;
}
+/*
+ pull a uint64_t from a cache entry
+*/
+static uint64_t centry_uint64_t(struct cache_entry *centry)
+{
+ uint64_t ret;
+
+ if (!centry_check_bytes(centry, 8)) {
+ smb_panic_fn("centry_uint64_t");
+ }
+ ret = BVAL(centry->data, centry->ofs);
+ centry->ofs += 8;
+ return ret;
+}
+
/*
pull a uint32 from a cache entry
*/
if (!centry_check_bytes(centry, 2)) {
smb_panic_fn("centry_uint16");
}
- ret = CVAL(centry->data, centry->ofs);
+ ret = SVAL(centry->data, centry->ofs);
centry->ofs += 2;
return ret;
}
}
ret = IVAL(centry->data, centry->ofs);
centry->ofs += 4;
- ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
+ ret += (uint64)IVAL(centry->data, centry->ofs) << 32;
centry->ofs += 4;
return ret;
}
smb_panic_fn("centry_string");
}
- ret = TALLOC_ARRAY(mem_ctx, char, len+1);
+ ret = talloc_array(mem_ctx, char, len+1);
if (!ret) {
smb_panic_fn("centry_string out of memory\n");
}
return NULL;
}
- ret = TALLOC_ARRAY(mem_ctx, char, 16);
+ ret = talloc_array(mem_ctx, char, 16);
if (!ret) {
smb_panic_fn("centry_hash out of memory\n");
}
ret = tdb_store_bystring(wcache->tdb, key_str,
make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
TALLOC_FREE(key_str);
- if (ret == -1) {
+ if (ret != 0) {
DEBUG(10, ("tdb_store_bystring failed: %s\n",
- tdb_errorstr(wcache->tdb)));
+ tdb_errorstr_compat(wcache->tdb)));
TALLOC_FREE(key_str);
return false;
}
}
/* if the server is down or the cache entry is not older than the
- current sequence number then it is OK */
- if (wcache_server_down(domain) ||
- centry->sequence_number == domain->sequence_number) {
+ current sequence number or it did not timeout then it is OK */
+ if (wcache_server_down(domain)
+ || ((centry->sequence_number == domain->sequence_number)
+ && (centry->timeout > time(NULL)))) {
DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
keystr, domain->name ));
return false;
TDB_DATA key;
key = string_tdb_data(kstr);
- data = tdb_fetch(wcache->tdb, key);
+ data = tdb_fetch_compat(wcache->tdb, key);
if (!data.dptr) {
/* a cache miss */
return NULL;
centry->len = data.dsize;
centry->ofs = 0;
- if (centry->len < 8) {
+ if (centry->len < 16) {
/* huh? corrupt cache? */
- DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
+ "(len < 16)?\n", kstr));
centry_free(centry);
return NULL;
}
centry->status = centry_ntstatus(centry);
centry->sequence_number = centry_uint32(centry);
+ centry->timeout = centry_uint64_t(centry);
return centry;
}
+static bool is_my_own_sam_domain(struct winbindd_domain *domain)
+{
+ if (strequal(domain->name, get_global_sam_name()) &&
+ sid_check_is_our_sam(&domain->sid)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool is_builtin_domain(struct winbindd_domain *domain)
+{
+ if (strequal(domain->name, "BUILTIN") &&
+ sid_check_is_builtin(&domain->sid)) {
+ return true;
+ }
+
+ return false;
+}
+
/*
fetch an entry from the cache, with a varargs key. auto-fetch the sequence
number and return status
char *kstr;
struct cache_entry *centry;
- if (!winbindd_use_cache()) {
+ if (!winbindd_use_cache() ||
+ is_my_own_sam_domain(domain) ||
+ is_builtin_domain(domain)) {
return NULL;
}
}
}
+/*
+ push a uint64_t into a centry
+*/
+static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
+{
+ centry_expand(centry, 8);
+ SBVAL(centry->data, centry->ofs, v);
+ centry->ofs += 8;
+}
+
/*
push a uint32 into a centry
*/
static void centry_put_uint16(struct cache_entry *centry, uint16 v)
{
centry_expand(centry, 2);
- SIVAL(centry->data, centry->ofs, v);
+ SSVAL(centry->data, centry->ofs, v);
centry->ofs += 2;
}
centry->ofs += 16;
}
-static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
+static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
{
fstring sid_string;
centry_put_string(centry, sid_to_fstring(sid_string, sid));
centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
centry->ofs = 0;
centry->sequence_number = domain->sequence_number;
+ centry->timeout = lp_winbind_cache_time() + time(NULL);
centry_put_ntstatus(centry, status);
centry_put_uint32(centry, centry->sequence_number);
+ centry_put_uint64_t(centry, centry->timeout);
return centry;
}
static void wcache_save_name_to_sid(struct winbindd_domain *domain,
NTSTATUS status, const char *domain_name,
- const char *name, const DOM_SID *sid,
+ const char *name, const struct dom_sid *sid,
enum lsa_SidType type)
{
struct cache_entry *centry;
centry_put_uint32(centry, type);
centry_put_sid(centry, sid);
fstrcpy(uname, name);
- strupper_m(uname);
+ (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)));
}
static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
- const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
+ const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
{
struct cache_entry *centry;
fstring sid_string;
}
centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
- DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
- name, nt_errstr(status)));
+ DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
+ domain_name, name, nt_errstr(status)));
centry_free(centry);
}
centry_put_string( centry, alias );
fstrcpy(uname, name);
- strupper_m(uname);
+ (void)strupper_m(uname);
centry_end(centry, "NSS/NA/%s", uname);
DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
centry_put_string( centry, name );
fstrcpy(uname, alias);
- strupper_m(uname);
+ (void)strupper_m(uname);
centry_end(centry, "NSS/AN/%s", uname);
DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
if ( (upper_name = SMB_STRDUP(name)) == NULL )
return NT_STATUS_NO_MEMORY;
- strupper_m(upper_name);
+ if (!strupper_m(upper_name)) {
+ SAFE_FREE(name);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
if ( (upper_name = SMB_STRDUP(alias)) == NULL )
return NT_STATUS_NO_MEMORY;
- strupper_m(upper_name);
+ if (!strupper_m(upper_name)) {
+ SAFE_FREE(alias);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
return status;
}
-NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
+NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
{
struct winbind_cache *cache = get_cache(domain);
TDB_DATA data;
fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
- data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
+ data = tdb_fetch_compat(cache->tdb, string_tdb_data(key_str));
if (!data.dptr) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *sid,
+ const struct dom_sid *sid,
const uint8 **cached_nt_pass,
const uint8 **cached_salt)
{
struct winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL;
NTSTATUS status;
- time_t t;
uint32 rid;
fstring tmp;
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- t = centry_time(centry);
+ /*
+ * We don't use the time element at this moment,
+ * but we have to consume it, so that we don't
+ * neet to change the disk format of the cache.
+ */
+ (void)centry_time(centry);
/* In the salted case this isn't actually the nt_hash itself,
but the MD5 of the salt + nt_hash. Let the caller
/* Store creds for a SID - only writes out new salted ones. */
NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- const DOM_SID *sid,
+ const struct dom_sid *sid,
const uint8 nt_pass[NT_HASH_LEN])
{
struct cache_entry *centry;
if (*num_entries == 0)
goto do_cached;
- (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
+ (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
if (! (*info)) {
smb_panic_fn("query_user_list out of memory");
}
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
- struct acct_info **info)
+ struct wb_acct_info **info)
{
struct winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL;
if (*num_entries == 0)
goto do_cached;
- (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+ (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
if (! (*info)) {
smb_panic_fn("enum_dom_groups out of memory");
}
static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
- struct acct_info **info)
+ struct wb_acct_info **info)
{
struct winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL;
if (*num_entries == 0)
goto do_cached;
- (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+ (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
if (! (*info)) {
smb_panic_fn("enum_dom_groups out of memory");
}
const char *domain_name,
const char *name,
uint32_t flags,
- DOM_SID *sid,
+ struct dom_sid *sid,
enum lsa_SidType *type)
{
NTSTATUS status;
/* Only save the reverse mapping if this was not a UPN */
if (!strchr(name, '@')) {
- strupper_m(CONST_DISCARD(char *,domain_name));
- strlower_m(CONST_DISCARD(char *,name));
+ if (!strupper_m(discard_const_p(char, domain_name))) {
+ 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);
}
}
given */
static NTSTATUS sid_to_name(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *sid,
+ const struct dom_sid *sid,
char **domain_name,
char **name,
enum lsa_SidType *type)
static NTSTATUS rids_to_names(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *domain_sid,
+ const struct dom_sid *domain_sid,
uint32 *rids,
size_t num_rids,
char **domain_name,
return NT_STATUS_OK;
}
- *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
- *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+ *names = talloc_array(mem_ctx, char *, num_rids);
+ *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
if ((*names == NULL) || (*types == NULL)) {
result = NT_STATUS_NO_MEMORY;
have_mapped = have_unmapped = false;
for (i=0; i<num_rids; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
struct cache_entry *centry;
fstring tmp;
(*names)[i] = centry_string(centry, *names);
- } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+ } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
+ || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
have_unmapped = true;
} else {
have_mapped = have_unmapped = false;
for (i=0; i<num_rids; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
struct cache_entry *centry;
fstring tmp;
*/
if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
for (i = 0; i < num_rids; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
const char *name = "";
const enum lsa_SidType type = SID_NAME_UNKNOWN;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
refresh_sequence_number(domain, false);
for (i=0; i<num_rids; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
NTSTATUS status;
if (!sid_compose(&sid, domain_sid, rids[i])) {
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *user_sid,
+ const struct dom_sid *user_sid,
struct wbint_userinfo *info)
{
NTSTATUS status;
/* Lookup groups a user is a member of. */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *user_sid,
- uint32 *num_groups, DOM_SID **user_gids)
+ const struct dom_sid *user_sid,
+ uint32 *num_groups, struct dom_sid **user_gids)
{
struct cache_entry *centry = NULL;
NTSTATUS status;
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 num_sids, const DOM_SID *sids,
+ uint32 num_sids, const struct dom_sid *sids,
uint32 *num_aliases, uint32 **alias_rids)
{
struct cache_entry *centry = NULL;
return NT_STATUS_OK;
}
- *sid_mem = talloc_array(mem_ctx, DOM_SID, *num_names);
+ *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
*names = talloc_array(mem_ctx, char *, *num_names);
*name_types = talloc_array(mem_ctx, uint32, *num_names);
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const DOM_SID *group_sid,
+ const struct dom_sid *group_sid,
enum lsa_SidType type,
uint32 *num_names,
- DOM_SID **sid_mem, char ***names,
+ struct dom_sid **sid_mem, char ***names,
uint32 **name_types)
{
struct cache_entry *centry = NULL;
}
do_fetch_cache:
- trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
+ trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
if (!trusts->array) {
TALLOC_FREE(dom_list);
return NT_STATUS_NO_MEMORY;
/* Invalidate the getpwnam and getgroups entries for a winbindd domain */
void wcache_invalidate_samlogon(struct winbindd_domain *domain,
- struct netr_SamInfo3 *info3)
+ const struct dom_sid *sid)
{
- DOM_SID sid;
fstring key_str, sid_string;
struct winbind_cache *cache;
return;
}
- sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
-
/* Clear U/SID cache entry */
- fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
+ fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
tdb_delete(cache->tdb, string_tdb_data(key_str));
/* Clear UG/SID cache entry */
- fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
+ fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
tdb_delete(cache->tdb, string_tdb_data(key_str));
/* Samba/winbindd never needs this. */
- netsamlogon_clear_cached_user(info3);
+ netsamlogon_clear_cached_user(sid);
}
bool wcache_invalidate_cache(void)
if (cache) {
if (cache->tdb) {
tdb_traverse(cache->tdb, traverse_fn, NULL);
+ /*
+ * Flushing cache has nothing to with domains.
+ * return here if we successfully flushed once.
+ * To avoid unnecessary traversing the cache.
+ */
+ return true;
} else {
return false;
}
return true;
/* when working offline we must not clear the cache on restart */
- wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
+ wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
- lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ TDB_INCOMPATIBLE_HASH |
+ (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
O_RDWR|O_CREAT, 0600);
if (wcache->tdb == NULL) {
tdb_close(wcache->tdb);
wcache->tdb = NULL;
- if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
+ if (unlink(state_path("winbindd_cache.tdb")) == -1) {
DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
- cache_path("winbindd_cache.tdb"),
+ state_path("winbindd_cache.tdb"),
strerror(errno) ));
return false;
}
/* Write the version. */
if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
- tdb_errorstr(wcache->tdb) ));
+ tdb_errorstr_compat(wcache->tdb) ));
return false;
}
}
}
}
-bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
char **domain_name, char **name,
enum lsa_SidType *type)
{
return NT_STATUS_IS_OK(status);
}
-bool lookup_cached_name(TALLOC_CTX *mem_ctx,
- const char *domain_name,
+bool lookup_cached_name(const char *domain_name,
const char *name,
- DOM_SID *sid,
+ struct dom_sid *sid,
enum lsa_SidType *type)
{
struct winbindd_domain *domain;
void cache_name2sid(struct winbindd_domain *domain,
const char *domain_name, const char *name,
- enum lsa_SidType type, const DOM_SID *sid)
+ enum lsa_SidType type, const struct dom_sid *sid)
{
refresh_sequence_number(domain, false);
wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
}
/* when working offline we must not clear the cache on restart */
- wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
+ wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
- lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ TDB_INCOMPATIBLE_HASH |
+ (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
O_RDWR|O_CREAT, 0600);
if (!wcache->tdb) {
return 0;
}
-NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
+NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
{
struct winbind_cache *cache = get_cache(domain);
NTSTATUS status;
ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
if (ret == 0) {
return NT_STATUS_OK;
- } else if ((ret == -1) || (wcache_cred_list == NULL)) {
+ } else if ((ret < 0) || (wcache_cred_list == NULL)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
TDB_DATA data;
time_t t;
- data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
+ data = tdb_fetch_compat(cache->tdb, string_tdb_data(cred->name));
if (!data.dptr) {
DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
cred->name));
centry->len = data.dsize;
centry->ofs = 0;
- if (centry->len < 8) {
+ if (centry->len < 16) {
/* huh? corrupt cache? */
- DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
+ "(len < 16) ?\n", kstr));
centry_free(centry);
state->bad_entry = true;
state->success = false;
centry->status = NT_STATUS(centry_uint32(centry));
centry->sequence_number = centry_uint32(centry);
+ centry->timeout = centry_uint64_t(centry);
return centry;
}
(void)centry_uint32(centry);
if (NT_STATUS_IS_OK(centry->status)) {
- DOM_SID sid;
+ struct dom_sid sid;
(void)centry_sid(centry, &sid);
}
struct tdb_validation_status *state)
{
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
- DOM_SID sid;
+ struct dom_sid sid;
if (!centry) {
return 1;
num_entries = (int32)centry_uint32(centry);
for (i=0; i< num_entries; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
(void)centry_string(centry, mem_ctx);
(void)centry_string(centry, mem_ctx);
(void)centry_string(centry, mem_ctx);
num_groups = centry_uint32(centry);
for (i=0; i< num_groups; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
centry_sid(centry, &sid);
}
num_names = centry_uint32(centry);
for (i=0; i< num_names; i++) {
- DOM_SID sid;
+ struct dom_sid sid;
centry_sid(centry, &sid);
(void)centry_string(centry, mem_ctx);
(void)centry_uint32(centry);
exit(47);
}
+static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
+ TDB_DATA key,
+ TDB_DATA data,
+ void *state)
+{
+ uint64_t ctimeout;
+ TDB_DATA blob;
+
+ if (is_non_centry_key(key)) {
+ return 0;
+ }
+
+ if (data.dptr == NULL || data.dsize == 0) {
+ if (tdb_delete(tdb, key) < 0) {
+ DEBUG(0, ("tdb_delete for [%s] failed!\n",
+ key.dptr));
+ return 1;
+ }
+ }
+
+ /* add timeout to blob (uint64_t) */
+ blob.dsize = data.dsize + 8;
+
+ blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
+ if (blob.dptr == NULL) {
+ return 1;
+ }
+ memset(blob.dptr, 0, blob.dsize);
+
+ /* copy status and seqnum */
+ memcpy(blob.dptr, data.dptr, 8);
+
+ /* add timeout */
+ ctimeout = lp_winbind_cache_time() + time(NULL);
+ SBVAL(blob.dptr, 8, ctimeout);
+
+ /* copy the rest */
+ memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
+
+ if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
+ DEBUG(0, ("tdb_store to update [%s] failed!\n",
+ key.dptr));
+ SAFE_FREE(blob.dptr);
+ return 1;
+ }
+
+ SAFE_FREE(blob.dptr);
+ return 0;
+}
+
+static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
+{
+ int rc;
+
+ DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
+
+ rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
+ if (rc < 0) {
+ return false;
+ }
+
+ return true;
+}
+
/***********************************************************************
Try and validate every entry in the winbindd cache. If we fail here,
delete the cache tdb and return non-zero.
int winbindd_validate_cache(void)
{
int ret = -1;
- const char *tdb_path = cache_path("winbindd_cache.tdb");
+ const char *tdb_path = state_path("winbindd_cache.tdb");
TDB_CONTEXT *tdb = NULL;
+ uint32_t vers_id;
+ bool ok;
DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
smb_panic_fn = validate_panic;
-
tdb = tdb_open_log(tdb_path,
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+ TDB_INCOMPATIBLE_HASH |
( lp_winbind_offline_logon()
? TDB_DEFAULT
: TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
"error opening/initializing tdb\n"));
goto done;
}
+
+ /* Version check and upgrade code. */
+ if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
+ DEBUG(10, ("Fresh database\n"));
+ tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
+ vers_id = WINBINDD_CACHE_VERSION;
+ }
+
+ if (vers_id != WINBINDD_CACHE_VERSION) {
+ if (vers_id == WINBINDD_CACHE_VER1) {
+ ok = wbcache_upgrade_v1_to_v2(tdb);
+ if (!ok) {
+ DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
+ unlink(tdb_path);
+ goto done;
+ }
+
+ tdb_store_uint32(tdb,
+ WINBINDD_CACHE_VERSION_KEYSTR,
+ WINBINDD_CACHE_VERSION);
+ vers_id = WINBINDD_CACHE_VER2;
+ }
+ }
+
tdb_close(tdb);
ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
int winbindd_validate_cache_nobackup(void)
{
int ret = -1;
- const char *tdb_path = cache_path("winbindd_cache.tdb");
+ const char *tdb_path = state_path("winbindd_cache.tdb");
DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
smb_panic_fn = validate_panic;
if ( !set_only ) {
if ( !*domains ) {
- list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
+ list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
idx = 0;
} else {
- list = TALLOC_REALLOC_ARRAY( *domains, *domains,
+ list = talloc_realloc( *domains, *domains,
struct winbindd_tdc_domain,
(*num_domains)+1);
idx = *num_domains;
return 0;
}
- list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
+ list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
if ( !list ) {
DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
return 0;
SAFE_FREE( data.dptr );
SAFE_FREE( key.dptr );
- return ( ret != -1 );
+ return ( ret == 0 );
}
/*********************************************************************
if ( !key.dptr )
return false;
- data = tdb_fetch( wcache->tdb, key );
+ data = tdb_fetch_compat( wcache->tdb, key );
SAFE_FREE( key.dptr );
DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
if ( !init_wcache() ) {
- return false;
+ return NULL;
}
/* fetch the list */
DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
name));
- d = TALLOC_P( ctx, struct winbindd_tdc_domain );
+ d = talloc( ctx, struct winbindd_tdc_domain );
if ( !d )
break;
return d;
}
+/*********************************************************************
+ ********************************************************************/
+
+struct winbindd_tdc_domain*
+ wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
+ const struct dom_sid *sid)
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_domains = 0;
+ int i;
+ struct winbindd_tdc_domain *d = NULL;
+
+ DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
+ sid_string_dbg(sid)));
+
+ if (!init_wcache()) {
+ return NULL;
+ }
+
+ /* fetch the list */
+
+ wcache_tdc_fetch_list(&dom_list, &num_domains);
+
+ for (i = 0; i<num_domains; i++) {
+ if (dom_sid_equal(sid, &(dom_list[i].sid))) {
+ DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
+ "Found domain %s for SID %s\n",
+ dom_list[i].domain_name,
+ sid_string_dbg(sid)));
+
+ d = talloc(ctx, struct winbindd_tdc_domain);
+ if (!d)
+ break;
+
+ d->domain_name = talloc_strdup(d,
+ dom_list[i].domain_name);
+
+ d->dns_name = talloc_strdup(d, dom_list[i].dns_name);
+ sid_copy(&d->sid, &dom_list[i].sid);
+ d->trust_flags = dom_list[i].trust_flags;
+ d->trust_type = dom_list[i].trust_type;
+ d->trust_attribs = dom_list[i].trust_attribs;
+
+ break;
+ }
+ }
+
+ TALLOC_FREE(dom_list);
+
+ return d;
+}
+
/*********************************************************************
********************************************************************/
static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
NTSTATUS status,
- const DOM_SID *user_sid,
+ const struct dom_sid *user_sid,
const char *homedir,
const char *shell,
const char *gecos,
centry_free(centry);
}
+#ifdef HAVE_ADS
+
NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
- const DOM_SID *user_sid,
+ const struct dom_sid *user_sid,
TALLOC_CTX *ctx,
- ADS_STRUCT *ads, LDAPMessage *msg,
const char **homedir, const char **shell,
const char **gecos, gid_t *p_gid)
{
do_query:
- nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
+ nt_status = nss_get_info( domain->name, user_sid, ctx,
homedir, shell, gecos, p_gid );
DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
return nt_status;
}
+#endif
/* the cache backend methods are exposed via this structure */
struct winbindd_methods cache_methods = {
TDB_DATA key, data;
bool ret = false;
- if (!wcache_opnum_cacheable(opnum)) {
+ if (!wcache_opnum_cacheable(opnum) ||
+ is_my_own_sam_domain(domain) ||
+ is_builtin_domain(domain)) {
return false;
}
if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
return false;
}
- data = tdb_fetch(wcache->tdb, key);
+ data = tdb_fetch_compat(wcache->tdb, key);
TALLOC_FREE(key.dptr);
if (data.dptr == NULL) {
return false;
}
- if (data.dsize < 4) {
+ if (data.dsize < 12) {
goto fail;
}
if (!is_domain_offline(domain)) {
uint32_t entry_seqnum, dom_seqnum, last_check;
+ uint64_t entry_timeout;
if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
&last_check)) {
(int)entry_seqnum));
goto fail;
}
+ entry_timeout = BVAL(data.dptr, 4);
+ if (time(NULL) > entry_timeout) {
+ DEBUG(10, ("Entry has timed out\n"));
+ goto fail;
+ }
}
- resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
- data.dsize - 4);
+ resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
+ data.dsize - 12);
if (resp->data == NULL) {
DEBUG(10, ("talloc failed\n"));
goto fail;
}
- resp->length = data.dsize - 4;
+ resp->length = data.dsize - 12;
ret = true;
fail:
{
TDB_DATA key, data;
uint32_t dom_seqnum, last_check;
+ uint64_t timeout;
- if (!wcache_opnum_cacheable(opnum)) {
+ if (!wcache_opnum_cacheable(opnum) ||
+ is_my_own_sam_domain(domain) ||
+ is_builtin_domain(domain)) {
return;
}
return;
}
- data.dsize = resp->length + 4;
+ timeout = time(NULL) + lp_winbind_cache_time();
+
+ data.dsize = resp->length + 12;
data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
if (data.dptr == NULL) {
goto done;
}
SIVAL(data.dptr, 0, dom_seqnum);
- memcpy(data.dptr+4, resp->data, resp->length);
+ SBVAL(data.dptr, 4, timeout);
+ memcpy(data.dptr + 12, resp->data, resp->length);
tdb_store(wcache->tdb, key, data, 0);