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"
28 #define CACHE_TYPE_NAME "NAM" /* Stores mapping from SID to name. */
29 #define CACHE_TYPE_SID "SID" /* Stores mapping from name to SID. */
31 /* Initialise caching system */
33 static TDB_CONTEXT *cache_tdb;
40 void winbindd_cache_init(void)
44 if (!(cache_tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0,
45 TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC,
47 DEBUG(0, ("Unable to open tdb cache - user and group caching disabled\n"));
50 /* find the sequence number for a domain */
52 static uint32 domain_sequence_number(struct winbindd_domain *domain)
57 uint16 switch_value = 2;
59 uint32 seqnum = DOM_SEQUENCE_NONE;
61 BOOL got_dom_pol = False;
62 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
64 if (!(mem_ctx = talloc_init()))
65 return DOM_SEQUENCE_NONE;
69 if (!(hnd = cm_get_sam_handle(domain->name)))
72 /* Get domain handle */
74 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
75 des_access, &domain->sid, &dom_pol);
77 if (!NT_STATUS_IS_OK(result))
82 /* Query domain info */
84 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
87 if (NT_STATUS_IS_OK(result))
88 seqnum = ctr.info.inf2.seq_num;
93 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
95 talloc_destroy(mem_ctx);
100 /* get the domain sequence number, possibly re-fetching */
102 static uint32 cached_sequence_number(struct winbindd_domain *domain)
106 struct cache_rec rec;
107 time_t t = time(NULL);
109 snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain->name);
110 dbuf = tdb_fetch_by_string(cache_tdb, keystr);
112 if (!dbuf.dptr || dbuf.dsize != sizeof(rec))
115 memcpy(&rec, dbuf.dptr, sizeof(rec));
116 SAFE_FREE(dbuf.dptr);
118 if (t < (rec.mod_time + lp_winbind_cache_time())) {
119 DEBUG(3,("cached sequence number for %s is %u\n",
120 domain->name, (unsigned)rec.seq_num));
125 rec.seq_num = domain_sequence_number(domain);
128 tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
133 /* Check whether a seq_num for a cached item has expired */
134 static BOOL cache_domain_expired(struct winbindd_domain *domain,
137 if (cached_sequence_number(domain) != seq_num) {
138 DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
146 static void set_cache_sequence_number(struct winbindd_domain *domain,
147 char *cache_type, char *subkey)
151 snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
152 domain->name, cache_type, subkey?subkey:"");
154 tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain));
157 static uint32 get_cache_sequence_number(struct winbindd_domain *domain,
158 char *cache_type, char *subkey)
163 snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
164 domain->name, cache_type, subkey ? subkey : "");
166 seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
168 DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
173 /* Fill the user or group cache with supplied data */
175 static void store_cache(struct winbindd_domain *domain, char *cache_type,
176 void *sam_entries, int buflen)
180 if (lp_winbind_cache_time() == 0)
185 if (!sam_entries || buflen == 0)
188 /* Store data as a mega-huge chunk in the tdb */
190 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
193 tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
195 /* Stamp cache with current seq number */
197 set_cache_sequence_number(domain, cache_type, NULL);
200 /* Fill the user cache with supplied data */
202 void winbindd_store_user_cache(struct winbindd_domain *domain,
203 struct getpwent_user *sam_entries,
206 DEBUG(3, ("storing user cache %s/%d entries\n", domain->name,
209 store_cache(domain, CACHE_TYPE_USER, sam_entries,
210 num_sam_entries * sizeof(struct getpwent_user));
213 /* Fill the group cache with supplied data */
215 void winbindd_store_group_cache(struct winbindd_domain *domain,
216 struct acct_info *sam_entries,
219 DEBUG(0, ("storing group cache %s/%d entries\n", domain->name,
222 store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
223 num_sam_entries * sizeof(struct acct_info));
226 static void store_cache_entry(struct winbindd_domain *domain, char *cache_type,
227 char *name, void *buf, int len)
231 /* Create key for store */
233 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type,
238 tdb_store_by_string(cache_tdb, keystr, buf, len);
241 /* Fill a name cache entry */
243 void winbindd_store_name_cache_entry(struct winbindd_domain *domain,
244 char *sid, struct winbindd_name *name)
246 if (lp_winbind_cache_time() == 0)
249 store_cache_entry(domain, CACHE_TYPE_NAME, sid, name,
250 sizeof(struct winbindd_name));
252 set_cache_sequence_number(domain, CACHE_TYPE_NAME, sid);
255 /* Fill a SID cache entry */
257 void winbindd_store_sid_cache_entry(struct winbindd_domain *domain,
258 char *name, struct winbindd_sid *sid)
260 if (lp_winbind_cache_time() == 0)
263 store_cache_entry(domain, CACHE_TYPE_SID, name, sid,
264 sizeof(struct winbindd_sid));
266 set_cache_sequence_number(domain, CACHE_TYPE_SID, name);
269 /* Fill a user info cache entry */
271 void winbindd_store_user_cache_entry(struct winbindd_domain *domain,
272 char *user_name, struct winbindd_pw *pw)
274 if (lp_winbind_cache_time() == 0)
277 store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
278 sizeof(struct winbindd_pw));
280 set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
283 /* Fill a user uid cache entry */
285 void winbindd_store_uid_cache_entry(struct winbindd_domain *domain, uid_t uid,
286 struct winbindd_pw *pw)
290 if (lp_winbind_cache_time() == 0)
293 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
295 DEBUG(3, ("storing uid cache entry %s/%s\n", domain->name, uidstr));
297 store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
298 sizeof(struct winbindd_pw));
300 set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
303 /* Fill a group info cache entry */
305 void winbindd_store_group_cache_entry(struct winbindd_domain *domain,
306 char *group_name, struct winbindd_gr *gr,
307 void *extra_data, int extra_data_len)
311 if (lp_winbind_cache_time() == 0)
314 DEBUG(3, ("storing group cache entry %s/%s\n", domain->name,
317 /* Fill group data */
319 store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
320 sizeof(struct winbindd_gr));
322 /* Fill extra data */
324 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
325 domain->name, group_name);
327 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
329 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
332 /* Fill a group info cache entry */
334 void winbindd_store_gid_cache_entry(struct winbindd_domain *domain, gid_t gid,
335 struct winbindd_gr *gr, void *extra_data,
341 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
343 if (lp_winbind_cache_time() == 0)
346 DEBUG(3, ("storing gid cache entry %s/%s\n", domain->name, gidstr));
348 /* Fill group data */
350 store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
351 sizeof(struct winbindd_gr));
353 /* Fill extra data */
355 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
356 domain->name, gidstr);
358 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
360 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
363 /* Fetch some cached user or group data */
365 static BOOL fetch_cache(struct winbindd_domain *domain, char *cache_type,
366 void **sam_entries, int *buflen)
371 if (lp_winbind_cache_time() == 0)
374 /* Parameter check */
376 if (!sam_entries || !buflen)
379 /* Check cache data is current */
381 if (cache_domain_expired(domain, get_cache_sequence_number(domain, cache_type, NULL)))
386 snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type, domain->name);
388 /* Fetch cache information */
390 data = tdb_fetch_by_string(cache_tdb, keystr);
395 /* Copy across cached data. We can save a memcpy() by directly
396 assigning the data.dptr to the sam_entries pointer. It will
397 be freed by the end{pw,gr}ent() function. */
399 *sam_entries = (struct acct_info *)data.dptr;
400 *buflen = data.dsize;
405 /* Return cached entries for a domain. Return false if there are no cached
406 entries, or the cached information has expired for the domain. */
408 BOOL winbindd_fetch_user_cache(struct winbindd_domain *domain,
409 struct getpwent_user **sam_entries,
415 result = fetch_cache(domain, CACHE_TYPE_USER,
416 (void **)sam_entries, &buflen);
418 *num_entries = buflen / sizeof(struct getpwent_user);
420 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
426 /* Return cached entries for a domain. Return false if there are no cached
427 entries, or the cached information has expired for the domain. */
429 BOOL winbindd_fetch_group_cache(struct winbindd_domain *domain,
430 struct acct_info **sam_entries,
436 result = fetch_cache(domain, CACHE_TYPE_GROUP,
437 (void **)sam_entries, &buflen);
439 *num_entries = buflen / sizeof(struct acct_info);
441 DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
447 static BOOL fetch_cache_entry(struct winbindd_domain *domain,
448 char *cache_type, char *name, void *buf, int len)
453 /* Create key for lookup */
455 snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain->name, name);
457 /* Look up cache entry */
459 data = tdb_fetch_by_string(cache_tdb, keystr);
464 /* Copy found entry into buffer */
466 memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
467 SAFE_FREE(data.dptr);
472 /* Fetch an individual SID cache entry */
474 BOOL winbindd_fetch_sid_cache_entry(struct winbindd_domain *domain,
475 char *name, struct winbindd_sid *sid)
479 if (lp_winbind_cache_time() == 0)
482 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_SID, name);
484 if (cache_domain_expired(domain, seq_num))
487 return fetch_cache_entry(domain, CACHE_TYPE_SID, name, sid,
488 sizeof(struct winbindd_sid));
491 /* Fetch an individual name cache entry */
493 BOOL winbindd_fetch_name_cache_entry(struct winbindd_domain *domain,
494 char *sid, struct winbindd_name *name)
498 if (lp_winbind_cache_time() == 0)
501 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_NAME, sid);
503 if (cache_domain_expired(domain, seq_num))
506 return fetch_cache_entry(domain, CACHE_TYPE_NAME, sid, name,
507 sizeof(struct winbindd_name));
510 /* Fetch an individual user cache entry */
512 BOOL winbindd_fetch_user_cache_entry(struct winbindd_domain *domain,
513 char *user, struct winbindd_pw *pw)
517 if (lp_winbind_cache_time() == 0)
520 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_USER, user);
522 if (cache_domain_expired(domain, seq_num))
525 return fetch_cache_entry(domain, CACHE_TYPE_USER, user, pw,
526 sizeof(struct winbindd_pw));
529 /* Fetch an individual uid cache entry */
531 BOOL winbindd_fetch_uid_cache_entry(struct winbindd_domain *domain, uid_t uid,
532 struct winbindd_pw *pw)
537 if (lp_winbind_cache_time() == 0)
540 snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
542 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
544 if (cache_domain_expired(domain, seq_num))
547 return fetch_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
548 sizeof(struct winbindd_pw));
551 /* Fetch an individual group cache entry. This function differs from the
552 user cache code as we need to store the group membership data. */
554 BOOL winbindd_fetch_group_cache_entry(struct winbindd_domain *domain,
555 char *group, struct winbindd_gr *gr,
556 void **extra_data, int *extra_data_len)
562 if (lp_winbind_cache_time() == 0)
565 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_GROUP, group);
567 if (cache_domain_expired(domain, seq_num))
570 /* Fetch group data */
572 if (!fetch_cache_entry(domain, CACHE_TYPE_GROUP, group, gr, sizeof(struct winbindd_gr)))
575 /* Fetch extra data */
577 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
578 domain->name, group);
580 data = tdb_fetch_by_string(cache_tdb, keystr);
585 /* Extra data freed when data has been sent */
588 *extra_data = data.dptr;
591 *extra_data_len = data.dsize;
597 /* Fetch an individual gid cache entry. This function differs from the
598 user cache code as we need to store the group membership data. */
600 BOOL winbindd_fetch_gid_cache_entry(struct winbindd_domain *domain, gid_t gid,
601 struct winbindd_gr *gr,
602 void **extra_data, int *extra_data_len)
609 snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
611 if (lp_winbind_cache_time() == 0)
614 seq_num = get_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
616 if (cache_domain_expired(domain, seq_num))
619 /* Fetch group data */
621 if (!fetch_cache_entry(domain, CACHE_TYPE_GROUP,
622 gidstr, gr, sizeof(struct winbindd_gr)))
625 /* Fetch extra data */
627 snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
628 domain->name, gidstr);
630 data = tdb_fetch_by_string(cache_tdb, keystr);
635 /* Extra data freed when data has been sent */
638 *extra_data = data.dptr;
641 *extra_data_len = data.dsize;
646 /* Flush cache data - easiest to just reopen the tdb */
648 void winbindd_flush_cache(void)
650 tdb_close(cache_tdb);
651 winbindd_cache_init();
654 /* Print cache status information */
656 void winbindd_cache_status(void)