26
26
#include "includes.h"
27
#include "system/filesys.h"
27
28
#include "winbindd.h"
28
29
#include "tdb_validate.h"
29
30
#include "../libcli/auth/libcli_auth.h"
30
31
#include "../librpc/gen_ndr/ndr_wbint.h"
34
#include "../libcli/security/security.h"
35
#include "passdb/machine_sid.h"
33
39
#define DBGC_CLASS DBGC_WINBIND
35
#define WINBINDD_CACHE_VERSION 1
41
#define WINBINDD_CACHE_VERSION 2
36
42
#define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
38
44
extern struct winbindd_methods reconnect_methods;
40
46
extern struct winbindd_methods ads_methods;
42
48
extern struct winbindd_methods builtin_passdb_methods;
49
extern struct winbindd_methods sam_passdb_methods;
45
52
* JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
103
111
static struct winbind_cache *wcache;
105
void winbindd_check_cache_size(time_t t)
107
static time_t last_check_time;
110
if (last_check_time == (time_t)0)
113
if (t - last_check_time < 60 && t - last_check_time > 0)
116
if (wcache == NULL || wcache->tdb == NULL) {
117
DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
121
if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
122
DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
126
if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
127
DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
128
(unsigned long)st.st_size,
129
(unsigned long)WINBINDD_MAX_CACHE_SIZE));
130
wcache_flush_cache();
134
113
/* get the winbind_cache structure */
135
114
static struct winbind_cache *get_cache(struct winbindd_domain *domain)
142
121
domain->backend = &builtin_passdb_methods;
143
122
domain->initialized = True;
125
if (strequal(domain->name, get_global_sam_name()) &&
126
sid_check_is_domain(&domain->sid)) {
127
domain->backend = &sam_passdb_methods;
128
domain->initialized = True;
145
131
if ( !domain->initialized ) {
146
132
init_dc_connection( domain );
212
pull a uint64_t from a cache entry
214
static uint64_t centry_uint64_t(struct cache_entry *centry)
218
if (!centry_check_bytes(centry, 8)) {
219
smb_panic_fn("centry_uint64_t");
221
ret = BVAL(centry->data, centry->ofs);
226
227
pull a uint32 from a cache entry
228
229
static uint32 centry_uint32(struct cache_entry *centry)
277
278
ret = IVAL(centry->data, centry->ofs);
278
279
centry->ofs += 4;
279
ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
280
ret += (uint64)IVAL(centry->data, centry->ofs) << 32;
280
281
centry->ofs += 4;
616
617
/* if the server is down or the cache entry is not older than the
617
current sequence number then it is OK */
618
if (wcache_server_down(domain) ||
619
centry->sequence_number == domain->sequence_number) {
618
current sequence number or it did not timeout then it is OK */
619
if (wcache_server_down(domain)
620
|| ((centry->sequence_number == domain->sequence_number)
621
&& (centry->timeout > time(NULL)))) {
620
622
DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
621
623
keystr, domain->name ));
647
649
centry->len = data.dsize;
650
if (centry->len < 8) {
652
if (centry->len < 16) {
651
653
/* huh? corrupt cache? */
652
DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
654
DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
655
"(len < 16)?\n", kstr));
653
656
centry_free(centry);
657
660
centry->status = centry_ntstatus(centry);
658
661
centry->sequence_number = centry_uint32(centry);
662
centry->timeout = centry_uint64_t(centry);
667
static bool is_my_own_sam_domain(struct winbindd_domain *domain)
669
if (strequal(domain->name, get_global_sam_name()) &&
670
sid_check_is_domain(&domain->sid)) {
677
static bool is_builtin_domain(struct winbindd_domain *domain)
679
if (strequal(domain->name, "BUILTIN") &&
680
sid_check_is_builtin(&domain->sid)) {
664
688
fetch an entry from the cache, with a varargs key. auto-fetch the sequence
665
689
number and return status
676
700
struct cache_entry *centry;
678
if (!winbindd_use_cache()) {
702
if (!winbindd_use_cache() ||
703
is_my_own_sam_domain(domain) ||
704
is_builtin_domain(domain)) {
771
push a uint64_t into a centry
773
static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
775
centry_expand(centry, 8);
776
SBVAL(centry->data, centry->ofs, v);
745
781
push a uint32 into a centry
747
783
static void centry_put_uint32(struct cache_entry *centry, uint32 v)
807
843
centry->ofs += 16;
810
static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
846
static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
812
848
fstring sid_string;
813
849
centry_put_string(centry, sid_to_fstring(sid_string, sid));
862
898
centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
864
900
centry->sequence_number = domain->sequence_number;
901
centry->timeout = lp_winbind_cache_time() + time(NULL);
865
902
centry_put_ntstatus(centry, status);
866
903
centry_put_uint32(centry, centry->sequence_number);
904
centry_put_uint64_t(centry, centry->timeout);
896
934
static void wcache_save_name_to_sid(struct winbindd_domain *domain,
897
935
NTSTATUS status, const char *domain_name,
898
const char *name, const DOM_SID *sid,
936
const char *name, const struct dom_sid *sid,
899
937
enum lsa_SidType type)
901
939
struct cache_entry *centry;
917
955
static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
918
const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
956
const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
920
958
struct cache_entry *centry;
921
959
fstring sid_string;
1215
NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
1253
NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1217
1255
struct winbind_cache *cache = get_cache(domain);
1248
1286
NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1249
1287
TALLOC_CTX *mem_ctx,
1288
const struct dom_sid *sid,
1251
1289
const uint8 **cached_nt_pass,
1252
1290
const uint8 **cached_salt)
1327
1365
/* Store creds for a SID - only writes out new salted ones. */
1329
1367
NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1330
TALLOC_CTX *mem_ctx,
1368
const struct dom_sid *sid,
1332
1369
const uint8 nt_pass[NT_HASH_LEN])
1334
1371
struct cache_entry *centry;
1525
1562
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1526
1563
TALLOC_CTX *mem_ctx,
1527
1564
uint32 *num_entries,
1528
struct acct_info **info)
1565
struct wb_acct_info **info)
1530
1567
struct winbind_cache *cache = get_cache(domain);
1531
1568
struct cache_entry *centry = NULL;
1547
1584
if (*num_entries == 0)
1548
1585
goto do_cached;
1550
(*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1587
(*info) = TALLOC_ARRAY(mem_ctx, struct wb_acct_info, *num_entries);
1551
1588
if (! (*info)) {
1552
1589
smb_panic_fn("enum_dom_groups out of memory");
1620
1657
static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1621
1658
TALLOC_CTX *mem_ctx,
1622
1659
uint32 *num_entries,
1623
struct acct_info **info)
1660
struct wb_acct_info **info)
1625
1662
struct winbind_cache *cache = get_cache(domain);
1626
1663
struct cache_entry *centry = NULL;
1642
1679
if (*num_entries == 0)
1643
1680
goto do_cached;
1645
(*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1682
(*info) = TALLOC_ARRAY(mem_ctx, struct wb_acct_info, *num_entries);
1646
1683
if (! (*info)) {
1647
1684
smb_panic_fn("enum_dom_groups out of memory");
1939
1976
static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1940
1977
TALLOC_CTX *mem_ctx,
1941
const DOM_SID *domain_sid,
1978
const struct dom_sid *domain_sid,
1943
1980
size_t num_rids,
1944
1981
char **domain_name,
2009
2046
(*names)[i] = centry_string(centry, *names);
2011
} else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2048
} else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2049
|| NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2012
2050
have_unmapped = true;
2110
2148
if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2111
2149
for (i = 0; i < num_rids; i++) {
2113
2151
const char *name = "";
2114
2152
const enum lsa_SidType type = SID_NAME_UNKNOWN;
2115
2153
NTSTATUS status = NT_STATUS_NONE_MAPPED;
2136
2174
refresh_sequence_number(domain, false);
2138
2176
for (i=0; i<num_rids; i++) {
2140
2178
NTSTATUS status;
2142
2180
if (!sid_compose(&sid, domain_sid, rids[i])) {
2222
2260
/* Lookup user information from a rid */
2223
2261
static NTSTATUS query_user(struct winbindd_domain *domain,
2224
2262
TALLOC_CTX *mem_ctx,
2225
const DOM_SID *user_sid,
2263
const struct dom_sid *user_sid,
2226
2264
struct wbint_userinfo *info)
2228
2266
NTSTATUS status;
2331
2369
/* Lookup groups a user is a member of. */
2332
2370
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2333
2371
TALLOC_CTX *mem_ctx,
2334
const DOM_SID *user_sid,
2335
uint32 *num_groups, DOM_SID **user_gids)
2372
const struct dom_sid *user_sid,
2373
uint32 *num_groups, struct dom_sid **user_gids)
2337
2375
struct cache_entry *centry = NULL;
2338
2376
NTSTATUS status;
2483
2521
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2484
2522
TALLOC_CTX *mem_ctx,
2485
uint32 num_sids, const DOM_SID *sids,
2523
uint32 num_sids, const struct dom_sid *sids,
2486
2524
uint32 *num_aliases, uint32 **alias_rids)
2488
2526
struct cache_entry *centry = NULL;
2586
2624
return NT_STATUS_OK;
2589
*sid_mem = talloc_array(mem_ctx, DOM_SID, *num_names);
2627
*sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2590
2628
*names = talloc_array(mem_ctx, char *, *num_names);
2591
2629
*name_types = talloc_array(mem_ctx, uint32, *num_names);
2616
2654
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2617
2655
TALLOC_CTX *mem_ctx,
2618
const DOM_SID *group_sid,
2656
const struct dom_sid *group_sid,
2619
2657
enum lsa_SidType type,
2620
2658
uint32 *num_names,
2621
DOM_SID **sid_mem, char ***names,
2659
struct dom_sid **sid_mem, char ***names,
2622
2660
uint32 **name_types)
2624
2662
struct cache_entry *centry = NULL;
2965
3003
/* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2967
3005
void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2968
struct netr_SamInfo3 *info3)
3006
const struct dom_sid *sid)
2971
3008
fstring key_str, sid_string;
2972
3009
struct winbind_cache *cache;
2990
sid_copy(&sid, info3->base.domain_sid);
2991
sid_append_rid(&sid, info3->base.rid);
2993
3027
/* Clear U/SID cache entry */
2994
fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
3028
fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
2995
3029
DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2996
3030
tdb_delete(cache->tdb, string_tdb_data(key_str));
2998
3032
/* Clear UG/SID cache entry */
2999
fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3033
fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3000
3034
DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3001
3035
tdb_delete(cache->tdb, string_tdb_data(key_str));
3003
3037
/* Samba/winbindd never needs this. */
3004
netsamlogon_clear_cached_user(info3);
3038
netsamlogon_clear_cached_user(sid);
3007
3041
bool wcache_invalidate_cache(void)
3061
bool wcache_invalidate_cache_noinit(void)
3063
struct winbindd_domain *domain;
3065
for (domain = domain_list(); domain; domain = domain->next) {
3066
struct winbind_cache *cache;
3068
/* Skip uninitialized domains. */
3069
if (!domain->initialized && !domain->internal) {
3073
cache = get_cache(domain);
3075
DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3076
"entries for %s\n", domain->name));
3079
tdb_traverse(cache->tdb, traverse_fn, NULL);
3081
* Flushing cache has nothing to with domains.
3082
* return here if we successfully flushed once.
3083
* To avoid unnecessary traversing the cache.
3027
3094
bool init_wcache(void)
3029
3096
if (wcache == NULL) {
3037
3104
/* when working offline we must not clear the cache on restart */
3038
3105
wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3039
3106
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3040
lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3107
TDB_INCOMPATIBLE_HASH |
3108
(lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3041
3109
O_RDWR|O_CREAT, 0600);
3043
3111
if (wcache->tdb == NULL) {
3117
bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
3185
bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3118
3186
char **domain_name, char **name,
3119
3187
enum lsa_SidType *type)
3130
3198
return NT_STATUS_IS_OK(status);
3133
bool lookup_cached_name(TALLOC_CTX *mem_ctx,
3134
const char *domain_name,
3201
bool lookup_cached_name(const char *domain_name,
3135
3202
const char *name,
3203
struct dom_sid *sid,
3137
3204
enum lsa_SidType *type)
3139
3206
struct winbindd_domain *domain;
3159
3226
void cache_name2sid(struct winbindd_domain *domain,
3160
3227
const char *domain_name, const char *name,
3161
enum lsa_SidType type, const DOM_SID *sid)
3228
enum lsa_SidType type, const struct dom_sid *sid)
3163
3230
refresh_sequence_number(domain, false);
3164
3231
wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3210
3277
/* when working offline we must not clear the cache on restart */
3211
3278
wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3212
3279
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3213
lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3280
TDB_INCOMPATIBLE_HASH |
3281
(lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3214
3282
O_RDWR|O_CREAT, 0600);
3216
3284
if (!wcache->tdb) {
3286
NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
3354
NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3288
3356
struct winbind_cache *cache = get_cache(domain);
3289
3357
NTSTATUS status;
3448
3516
centry->len = data.dsize;
3449
3517
centry->ofs = 0;
3451
if (centry->len < 8) {
3519
if (centry->len < 16) {
3452
3520
/* huh? corrupt cache? */
3453
DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3521
DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3522
"(len < 16) ?\n", kstr));
3454
3523
centry_free(centry);
3455
3524
state->bad_entry = true;
3456
3525
state->success = false;
3632
3702
num_entries = (int32)centry_uint32(centry);
3634
3704
for (i=0; i< num_entries; i++) {
3636
3706
(void)centry_string(centry, mem_ctx);
3637
3707
(void)centry_string(centry, mem_ctx);
3638
3708
(void)centry_string(centry, mem_ctx);
3741
3811
num_names = centry_uint32(centry);
3743
3813
for (i=0; i< num_names; i++) {
3745
3815
centry_sid(centry, &sid);
3746
3816
(void)centry_string(centry, mem_ctx);
3747
3817
(void)centry_uint32(centry);
4029
4099
tdb = tdb_open_log(tdb_path,
4030
4100
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4101
TDB_INCOMPATIBLE_HASH |
4031
4102
( lp_winbind_offline_logon()
4033
4104
: TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4546
/*********************************************************************
4547
********************************************************************/
4549
struct winbindd_tdc_domain*
4550
wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
4551
const struct dom_sid *sid)
4553
struct winbindd_tdc_domain *dom_list = NULL;
4554
size_t num_domains = 0;
4556
struct winbindd_tdc_domain *d = NULL;
4558
DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4559
sid_string_dbg(sid)));
4561
if (!init_wcache()) {
4565
/* fetch the list */
4567
wcache_tdc_fetch_list(&dom_list, &num_domains);
4569
for (i = 0; i<num_domains; i++) {
4570
if (sid_equal(sid, &(dom_list[i].sid))) {
4571
DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4572
"Found domain %s for SID %s\n",
4573
dom_list[i].domain_name,
4574
sid_string_dbg(sid)));
4576
d = TALLOC_P(ctx, struct winbindd_tdc_domain);
4580
d->domain_name = talloc_strdup(d,
4581
dom_list[i].domain_name);
4583
d->dns_name = talloc_strdup(d, dom_list[i].dns_name);
4584
sid_copy(&d->sid, &dom_list[i].sid);
4585
d->trust_flags = dom_list[i].trust_flags;
4586
d->trust_type = dom_list[i].trust_type;
4587
d->trust_attribs = dom_list[i].trust_attribs;
4593
TALLOC_FREE(dom_list);
4476
4599
/*********************************************************************
4477
4600
********************************************************************/
4516
4639
centry_free(centry);
4519
4644
NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4520
const DOM_SID *user_sid,
4645
const struct dom_sid *user_sid,
4521
4646
TALLOC_CTX *ctx,
4522
ADS_STRUCT *ads, LDAPMessage *msg,
4523
4647
const char **homedir, const char **shell,
4524
4648
const char **gecos, gid_t *p_gid)
4554
nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4678
nt_status = nss_get_info( domain->name, user_sid, ctx,
4555
4679
homedir, shell, gecos, p_gid );
4557
4681
DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4657
4784
if (data.dptr == NULL) {
4660
if (data.dsize < 4) {
4787
if (data.dsize < 12) {
4664
4791
if (!is_domain_offline(domain)) {
4665
4792
uint32_t entry_seqnum, dom_seqnum, last_check;
4793
uint64_t entry_timeout;
4667
4795
if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4668
4796
&last_check)) {
4674
4802
(int)entry_seqnum));
4805
entry_timeout = BVAL(data.dptr, 4);
4806
if (time(NULL) > entry_timeout) {
4807
DEBUG(10, ("Entry has timed out\n"));
4679
resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4812
resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4681
4814
if (resp->data == NULL) {
4682
4815
DEBUG(10, ("talloc failed\n"));
4685
resp->length = data.dsize - 4;
4818
resp->length = data.dsize - 12;
4696
4829
TDB_DATA key, data;
4697
4830
uint32_t dom_seqnum, last_check;
4699
if (!wcache_opnum_cacheable(opnum)) {
4833
if (!wcache_opnum_cacheable(opnum) ||
4834
is_my_own_sam_domain(domain) ||
4835
is_builtin_domain(domain)) {
4717
data.dsize = resp->length + 4;
4853
timeout = time(NULL) + lp_winbind_cache_time();
4855
data.dsize = resp->length + 12;
4718
4856
data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4719
4857
if (data.dptr == NULL) {
4723
4861
SIVAL(data.dptr, 0, dom_seqnum);
4724
memcpy(data.dptr+4, resp->data, resp->length);
4862
SBVAL(data.dptr, 4, timeout);
4863
memcpy(data.dptr + 12, resp->data, resp->length);
4726
4865
tdb_store(wcache->tdb, key, data, 0);