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(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 "
50 /* get the domain sequence number, possibly re-fetching */
51 static uint32 cached_sequence_number(char *domain_name)
56 time_t t = time(NULL);
58 snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
59 dbuf = tdb_fetch_by_string(cache_tdb, keystr);
60 if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
63 memcpy(&rec, dbuf.dptr, sizeof(rec));
66 if (t < (rec.mod_time + lp_winbind_cache_time())) {
67 DEBUG(3,("cached sequence number for %s is %u\n",
68 domain_name, (unsigned)rec.seq_num));
73 rec.seq_num = domain_sequence_number(domain_name);
75 tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
80 /* Check whether a seq_num for a cached item has expired */
81 static BOOL cache_domain_expired(char *domain_name, uint32 seq_num)
83 if (cached_sequence_number(domain_name) != seq_num) {
84 DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
91 static void set_cache_sequence_number(char *domain_name, char *cache_type,
96 snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
97 domain_name, cache_type, subkey?subkey:"");
99 tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
102 static uint32 get_cache_sequence_number(char *domain_name, char *cache_type,
108 snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
109 domain_name, cache_type, subkey?subkey:"");
110 seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
112 DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
117 /* Fill the user or group cache with supplied data */
119 static void store_cache(char *domain_name, char *cache_type,
120 void *sam_entries, int buflen)
124 if (lp_winbind_cache_time() == 0) return;
127 if (!sam_entries || buflen == 0) return;
129 /* Store data as a mega-huge chunk in the tdb */
130 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
133 tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
135 /* Stamp cache with current seq number */
136 set_cache_sequence_number(domain_name, cache_type, NULL);
139 /* Fill the user cache with supplied data */
141 void winbindd_store_user_cache(char *domain,
142 struct getpwent_user *sam_entries,
145 DEBUG(3, ("storing user cache %s/%d entries\n", domain,
148 store_cache(domain, CACHE_TYPE_USER, sam_entries,
149 num_sam_entries * sizeof(struct getpwent_user));
152 /* Fill the group cache with supplied data */
154 void winbindd_store_group_cache(char *domain,
155 struct acct_info *sam_entries,
158 DEBUG(0, ("storing group cache %s/%d entries\n", domain,
161 store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
162 num_sam_entries * sizeof(struct acct_info));
165 static void store_cache_entry(char *domain, char *cache_type, char *name,
170 /* Create key for store */
171 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
174 tdb_store_by_string(cache_tdb, keystr, buf, len);
177 /* Fill a user info cache entry */
179 void winbindd_store_user_cache_entry(char *domain, char *user_name,
180 struct winbindd_pw *pw)
182 if (lp_winbind_cache_time() == 0) return;
184 store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
185 sizeof(struct winbindd_pw));
187 set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
190 /* Fill a user uid cache entry */
192 void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
193 struct winbindd_pw *pw)
197 if (lp_winbind_cache_time() == 0) return;
199 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
201 DEBUG(3, ("storing uid cache entry %s/%s\n", domain, uidstr));
203 store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
204 sizeof(struct winbindd_pw));
206 set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
209 /* Fill a group info cache entry */
210 void winbindd_store_group_cache_entry(char *domain, char *group_name,
211 struct winbindd_gr *gr, void *extra_data,
216 if (lp_winbind_cache_time() == 0) return;
218 DEBUG(3, ("storing group cache entry %s/%s\n", domain, group_name));
220 /* Fill group data */
222 store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
223 sizeof(struct winbindd_gr));
225 /* Fill extra data */
227 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
229 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
231 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
234 /* Fill a group info cache entry */
236 void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
237 struct winbindd_gr *gr, void *extra_data,
243 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
245 if (lp_winbind_cache_time() == 0) return;
247 DEBUG(3, ("storing gid cache entry %s/%s\n", domain, gidstr));
249 /* Fill group data */
251 store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
252 sizeof(struct winbindd_gr));
254 /* Fill extra data */
256 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
259 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
261 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
264 /* Fetch some cached user or group data */
265 static BOOL fetch_cache(char *domain_name, char *cache_type,
266 void **sam_entries, int *buflen)
271 if (lp_winbind_cache_time() == 0) return False;
273 /* Parameter check */
274 if (!sam_entries || !buflen) {
278 /* Check cache data is current */
279 if (cache_domain_expired(domain_name,
280 get_cache_sequence_number(domain_name,
287 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
290 /* Fetch cache information */
291 data = tdb_fetch_by_string(cache_tdb, keystr);
293 if (!data.dptr) return False;
295 /* Copy across cached data. We can save a memcpy() by directly
296 assigning the data.dptr to the sam_entries pointer. It will
297 be freed by the end{pw,gr}ent() function. */
299 *sam_entries = (struct acct_info *)data.dptr;
300 *buflen = data.dsize;
305 /* Return cached entries for a domain. Return false if there are no cached
306 entries, or the cached information has expired for the domain. */
308 BOOL winbindd_fetch_user_cache(char *domain_name,
309 struct getpwent_user **sam_entries,
315 result = fetch_cache(domain_name, CACHE_TYPE_USER,
316 (void **)sam_entries, &buflen);
318 *num_entries = buflen / sizeof(struct getpwent_user);
320 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
326 /* Return cached entries for a domain. Return false if there are no cached
327 entries, or the cached information has expired for the domain. */
329 BOOL winbindd_fetch_group_cache(char *domain_name,
330 struct acct_info **sam_entries,
336 result = fetch_cache(domain_name, CACHE_TYPE_GROUP,
337 (void **)sam_entries, &buflen);
339 *num_entries = buflen / sizeof(struct acct_info);
341 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
347 static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name,
353 /* Create key for lookup */
354 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
356 /* Look up cache entry */
357 data = tdb_fetch_by_string(cache_tdb, keystr);
358 if (!data.dptr) return False;
360 /* Copy found entry into buffer */
361 memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
366 /* Fetch an individual user cache entry */
367 BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
368 struct winbindd_pw *pw)
372 if (lp_winbind_cache_time() == 0) return False;
374 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
376 if (cache_domain_expired(domain_name, seq_num)) return False;
378 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw,
379 sizeof(struct winbindd_pw));
382 /* Fetch an individual uid cache entry */
383 BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
384 struct winbindd_pw *pw)
389 if (lp_winbind_cache_time() == 0) return False;
391 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
392 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
394 if (cache_domain_expired(domain_name, seq_num)) return False;
396 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw,
397 sizeof(struct winbindd_pw));
400 /* Fetch an individual group cache entry. This function differs from the
401 user cache code as we need to store the group membership data. */
403 BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
404 struct winbindd_gr *gr,
405 void **extra_data, int *extra_data_len)
411 if (lp_winbind_cache_time() == 0) return False;
413 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
416 if (cache_domain_expired(domain_name, seq_num)) return False;
418 /* Fetch group data */
419 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr,
420 sizeof(struct winbindd_gr))) {
424 /* Fetch extra data */
425 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
428 data = tdb_fetch_by_string(cache_tdb, keystr);
430 if (!data.dptr) return False;
432 /* Extra data freed when data has been sent */
433 if (extra_data) *extra_data = data.dptr;
434 if (extra_data_len) *extra_data_len = data.dsize;
440 /* Fetch an individual gid cache entry. This function differs from the
441 user cache code as we need to store the group membership data. */
443 BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
444 struct winbindd_gr *gr,
445 void **extra_data, int *extra_data_len)
452 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
454 if (lp_winbind_cache_time() == 0) return False;
456 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
459 if (cache_domain_expired(domain_name, seq_num)) return False;
461 /* Fetch group data */
462 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
463 gidstr, gr, sizeof(struct winbindd_gr))) {
467 /* Fetch extra data */
468 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
469 domain_name, gidstr);
470 data = tdb_fetch_by_string(cache_tdb, keystr);
471 if (!data.dptr) return False;
473 /* Extra data freed when data has been sent */
474 if (extra_data) *extra_data = data.dptr;
475 if (extra_data_len) *extra_data_len = data.dsize;
480 /* Flush cache data - easiest to just reopen the tdb */
481 void winbindd_flush_cache(void)
483 tdb_close(cache_tdb);
484 winbindd_cache_init();
487 /* Print cache status information */
488 void winbindd_cache_dump_status(void)