2 Unix SMB/Netbios implementation.
5 Winbind daemon - caching related functions
7 Copyright (C) Tim Potter 2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define CACHE_TYPE_USER "USR"
27 #define CACHE_TYPE_GROUP "GRP"
29 /* Initialise caching system */
31 static TDB_CONTEXT *cache_tdb;
38 void winbindd_cache_init(void)
42 if (!(cache_tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0,
43 TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC,
45 DEBUG(0, ("Unable to open tdb cache - user and group caching "
49 /* find the sequence number for a domain */
51 static uint32 domain_sequence_number(struct winbindd_domain *domain)
56 uint16 switch_value = 2;
58 uint32 seqnum = DOM_SEQUENCE_NONE;
60 if (!(mem_ctx = talloc_init()))
61 return DOM_SEQUENCE_NONE;
63 if (!(hnd = cm_get_sam_dom_handle(domain->name, &domain->sid)))
66 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &hnd->pol,
69 if (NT_STATUS_IS_OK(result))
70 seqnum = ctr.info.inf2.seq_num;
73 talloc_destroy(mem_ctx);
78 /* get the domain sequence number, possibly re-fetching */
80 static uint32 cached_sequence_number(struct winbindd_domain *domain)
85 time_t t = time(NULL);
87 snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain->name);
88 dbuf = tdb_fetch_by_string(cache_tdb, keystr);
90 if (!dbuf.dptr || dbuf.dsize != sizeof(rec))
93 memcpy(&rec, dbuf.dptr, sizeof(rec));
96 if (t < (rec.mod_time + lp_winbind_cache_time())) {
97 DEBUG(3,("cached sequence number for %s is %u\n",
98 domain->name, (unsigned)rec.seq_num));
103 rec.seq_num = domain_sequence_number(domain);
106 tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
111 /* Check whether a seq_num for a cached item has expired */
112 static BOOL cache_domain_expired(struct winbindd_domain *domain,
115 if (cached_sequence_number(domain) != seq_num) {
116 DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
124 static void set_cache_sequence_number(struct winbindd_domain *domain,
125 char *cache_type, char *subkey)
129 snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
130 domain->name, cache_type, subkey?subkey:"");
132 tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain));
135 static uint32 get_cache_sequence_number(struct winbindd_domain *domain,
136 char *cache_type, char *subkey)
141 snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
142 domain->name, cache_type, subkey ? subkey : "");
144 seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
146 DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
151 /* Fill the user or group cache with supplied data */
153 static void store_cache(struct winbindd_domain *domain, char *cache_type,
154 void *sam_entries, int buflen)
158 if (lp_winbind_cache_time() == 0)
163 if (!sam_entries || buflen == 0)
166 /* Store data as a mega-huge chunk in the tdb */
168 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
171 tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
173 /* Stamp cache with current seq number */
175 set_cache_sequence_number(domain, cache_type, NULL);
178 /* Fill the user cache with supplied data */
180 void winbindd_store_user_cache(struct winbindd_domain *domain,
181 struct getpwent_user *sam_entries,
184 DEBUG(3, ("storing user cache %s/%d entries\n", domain->name,
187 store_cache(domain, CACHE_TYPE_USER, sam_entries,
188 num_sam_entries * sizeof(struct getpwent_user));
191 /* Fill the group cache with supplied data */
193 void winbindd_store_group_cache(struct winbindd_domain *domain,
194 struct acct_info *sam_entries,
197 DEBUG(0, ("storing group cache %s/%d entries\n", domain->name,
200 store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
201 num_sam_entries * sizeof(struct acct_info));
204 static void store_cache_entry(struct winbindd_domain *domain, char *cache_type,
205 char *name, void *buf, int len)
209 /* Create key for store */
211 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type,
216 tdb_store_by_string(cache_tdb, keystr, buf, len);
219 /* Fill a user info cache entry */
221 void winbindd_store_user_cache_entry(struct winbindd_domain *domain,
222 char *user_name, struct winbindd_pw *pw)
224 if (lp_winbind_cache_time() == 0)
227 store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
228 sizeof(struct winbindd_pw));
230 set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
233 /* Fill a user uid cache entry */
235 void winbindd_store_uid_cache_entry(struct winbindd_domain *domain, uid_t uid,
236 struct winbindd_pw *pw)
240 if (lp_winbind_cache_time() == 0) return;
242 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
244 DEBUG(3, ("storing uid cache entry %s/%s\n", domain->name, uidstr));
246 store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
247 sizeof(struct winbindd_pw));
249 set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
252 /* Fill a group info cache entry */
254 void winbindd_store_group_cache_entry(struct winbindd_domain *domain,
255 char *group_name, struct winbindd_gr *gr,
256 void *extra_data, int extra_data_len)
260 if (lp_winbind_cache_time() == 0)
263 DEBUG(3, ("storing group cache entry %s/%s\n", domain->name,
266 /* Fill group data */
268 store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
269 sizeof(struct winbindd_gr));
271 /* Fill extra data */
273 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
274 domain->name, group_name);
276 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
278 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
281 /* Fill a group info cache entry */
283 void winbindd_store_gid_cache_entry(struct winbindd_domain *domain, gid_t gid,
284 struct winbindd_gr *gr, void *extra_data,
290 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
292 if (lp_winbind_cache_time() == 0)
295 DEBUG(3, ("storing gid cache entry %s/%s\n", domain->name, gidstr));
297 /* Fill group data */
299 store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
300 sizeof(struct winbindd_gr));
302 /* Fill extra data */
304 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
305 domain->name, gidstr);
307 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
309 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
312 /* Fetch some cached user or group data */
314 static BOOL fetch_cache(struct winbindd_domain *domain, char *cache_type,
315 void **sam_entries, int *buflen)
320 if (lp_winbind_cache_time() == 0)
323 /* Parameter check */
325 if (!sam_entries || !buflen)
328 /* Check cache data is current */
330 if (cache_domain_expired(
331 domain, get_cache_sequence_number(domain, cache_type, NULL)))
336 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
339 /* Fetch cache information */
341 data = tdb_fetch_by_string(cache_tdb, keystr);
346 /* Copy across cached data. We can save a memcpy() by directly
347 assigning the data.dptr to the sam_entries pointer. It will
348 be freed by the end{pw,gr}ent() function. */
350 *sam_entries = (struct acct_info *)data.dptr;
351 *buflen = data.dsize;
356 /* Return cached entries for a domain. Return false if there are no cached
357 entries, or the cached information has expired for the domain. */
359 BOOL winbindd_fetch_user_cache(struct winbindd_domain *domain,
360 struct getpwent_user **sam_entries,
366 result = fetch_cache(domain, CACHE_TYPE_USER,
367 (void **)sam_entries, &buflen);
369 *num_entries = buflen / sizeof(struct getpwent_user);
371 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
377 /* Return cached entries for a domain. Return false if there are no cached
378 entries, or the cached information has expired for the domain. */
380 BOOL winbindd_fetch_group_cache(struct winbindd_domain *domain,
381 struct acct_info **sam_entries,
387 result = fetch_cache(domain, CACHE_TYPE_GROUP,
388 (void **)sam_entries, &buflen);
390 *num_entries = buflen / sizeof(struct acct_info);
392 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
398 static BOOL fetch_cache_entry(struct winbindd_domain *domain,
399 char *cache_type, char *name, void *buf, int len)
404 /* Create key for lookup */
406 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type,
409 /* Look up cache entry */
411 data = tdb_fetch_by_string(cache_tdb, keystr);
416 /* Copy found entry into buffer */
418 memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
419 SAFE_FREE(data.dptr);
424 /* Fetch an individual user cache entry */
426 BOOL winbindd_fetch_user_cache_entry(struct winbindd_domain *domain,
427 char *user, struct winbindd_pw *pw)
431 if (lp_winbind_cache_time() == 0)
434 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_USER,
437 if (cache_domain_expired(domain, seq_num))
440 return fetch_cache_entry(domain, CACHE_TYPE_USER, user, pw,
441 sizeof(struct winbindd_pw));
444 /* Fetch an individual uid cache entry */
446 BOOL winbindd_fetch_uid_cache_entry(struct winbindd_domain *domain, uid_t uid,
447 struct winbindd_pw *pw)
452 if (lp_winbind_cache_time() == 0)
455 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
457 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_USER,
460 if (cache_domain_expired(domain, seq_num))
463 return fetch_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
464 sizeof(struct winbindd_pw));
467 /* Fetch an individual group cache entry. This function differs from the
468 user cache code as we need to store the group membership data. */
470 BOOL winbindd_fetch_group_cache_entry(struct winbindd_domain *domain,
471 char *group, struct winbindd_gr *gr,
472 void **extra_data, int *extra_data_len)
478 if (lp_winbind_cache_time() == 0)
481 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_GROUP,
484 if (cache_domain_expired(domain, seq_num))
487 /* Fetch group data */
489 if (!fetch_cache_entry(domain, CACHE_TYPE_GROUP, group, gr,
490 sizeof(struct winbindd_gr)))
493 /* Fetch extra data */
495 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
496 domain->name, group);
498 data = tdb_fetch_by_string(cache_tdb, keystr);
503 /* Extra data freed when data has been sent */
506 *extra_data = data.dptr;
509 *extra_data_len = data.dsize;
515 /* Fetch an individual gid cache entry. This function differs from the
516 user cache code as we need to store the group membership data. */
518 BOOL winbindd_fetch_gid_cache_entry(struct winbindd_domain *domain, gid_t gid,
519 struct winbindd_gr *gr,
520 void **extra_data, int *extra_data_len)
527 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
529 if (lp_winbind_cache_time() == 0)
532 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_GROUP,
535 if (cache_domain_expired(domain, seq_num))
538 /* Fetch group data */
540 if (!fetch_cache_entry(domain, CACHE_TYPE_GROUP,
541 gidstr, gr, sizeof(struct winbindd_gr)))
544 /* Fetch extra data */
546 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
547 domain->name, gidstr);
549 data = tdb_fetch_by_string(cache_tdb, keystr);
554 /* Extra data freed when data has been sent */
557 *extra_data = data.dptr;
560 *extra_data_len = data.dsize;
565 /* Flush cache data - easiest to just reopen the tdb */
567 void winbindd_flush_cache(void)
569 tdb_close(cache_tdb);
570 winbindd_cache_init();
573 /* Print cache status information */
575 void winbindd_cache_dump_status(void)