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)
41 unlink(lock_path("winbindd_cache.tdb"));
42 if (!(cache_tdb = tdb_open(lock_path("winbindd_cache.tdb"), 0,
44 O_RDWR | O_CREAT, 0600))) {
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 slprintf(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(4,("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(4,("seq %u for %s has expired\n", (unsigned)seq_num, domain_name));
90 static void set_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
93 slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
94 domain_name, cache_type, subkey?subkey:"");
95 tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
98 static uint32 get_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
102 slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
103 domain_name, cache_type, subkey?subkey:"");
104 seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
105 DEBUG(4,("%s is %u\n", keystr, (unsigned)seq_num));
109 /* Fill the user or group cache with supplied data */
110 static void fill_cache(char *domain_name, char *cache_type,
111 struct acct_info *sam_entries,
116 if (lp_winbind_cache_time() == 0) return;
119 if (!sam_entries || (num_sam_entries == 0)) return;
121 DEBUG(4, ("filling %s cache for domain %s with %d entries\n",
122 cache_type, domain_name, num_sam_entries));
124 /* Store data as a mega-huge chunk in the tdb */
125 slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
128 tdb_store_by_string(cache_tdb, keystr,
129 sam_entries, sizeof(struct acct_info) * num_sam_entries);
131 /* Stamp cache with current seq number */
132 set_cache_sequence_number(domain_name, cache_type, NULL);
135 /* Fill the user cache with supplied data */
137 void winbindd_fill_user_cache(char *domain_name,
138 struct acct_info *sam_entries,
141 fill_cache(domain_name, CACHE_TYPE_USER, sam_entries, num_sam_entries);
144 /* Fill the group cache with supplied data */
146 void winbindd_fill_group_cache(char *domain_name,
147 struct acct_info *sam_entries,
150 fill_cache(domain_name, CACHE_TYPE_GROUP, sam_entries, num_sam_entries);
153 static void fill_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
157 /* Create key for store */
158 slprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
160 DEBUG(4, ("filling cache entry %s\n", keystr));
163 tdb_store_by_string(cache_tdb, keystr, buf, len);
166 /* Fill a user info cache entry */
167 void winbindd_fill_user_cache_entry(char *domain, char *user_name,
168 struct winbindd_pw *pw)
170 if (lp_winbind_cache_time() == 0) return;
172 fill_cache_entry(domain, CACHE_TYPE_USER, user_name, pw, sizeof(struct winbindd_pw));
173 set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
176 /* Fill a user uid cache entry */
177 void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
178 struct winbindd_pw *pw)
182 if (lp_winbind_cache_time() == 0) return;
184 slprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
185 fill_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
186 set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
189 /* Fill a group info cache entry */
190 void winbindd_fill_group_cache_entry(char *domain, char *group_name,
191 struct winbindd_gr *gr, void *extra_data,
196 if (lp_winbind_cache_time() == 0) return;
198 /* Fill group data */
199 fill_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr, sizeof(struct winbindd_gr));
201 /* Fill extra data */
202 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, group_name);
203 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
205 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
208 /* Fill a group info cache entry */
209 void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
210 struct winbindd_gr *gr, void *extra_data,
216 slprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
218 if (lp_winbind_cache_time() == 0) return;
220 /* Fill group data */
221 fill_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr, sizeof(struct winbindd_gr));
223 /* Fill extra data */
224 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, gidstr);
225 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
227 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
230 /* Fetch some cached user or group data */
231 static BOOL fetch_cache(char *domain_name, char *cache_type,
232 struct acct_info **sam_entries, int *num_sam_entries)
237 if (lp_winbind_cache_time() == 0) return False;
239 /* Parameter check */
240 if (!sam_entries || !num_sam_entries) {
244 /* Check cache data is current */
245 if (cache_domain_expired(domain_name,
246 get_cache_sequence_number(domain_name, cache_type, NULL))) {
251 slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
254 /* Fetch cache information */
255 data = tdb_fetch_by_string(cache_tdb, keystr);
257 if (!data.dptr) return False;
259 /* Copy across cached data. We can save a memcpy() by directly
260 assigning the data.dptr to the sam_entries pointer. It will
261 be freed by the end{pw,gr}ent() function. */
263 *sam_entries = (struct acct_info *)data.dptr;
264 *num_sam_entries = data.dsize / sizeof(struct acct_info);
266 DEBUG(4, ("fetched %d cached %s entries for domain %s\n",
267 *num_sam_entries, cache_type, domain_name));
272 /* Return cached entries for a domain. Return false if there are no cached
273 entries, or the cached information has expired for the domain. */
275 BOOL winbindd_fetch_user_cache(char *domain_name,
276 struct acct_info **sam_entries,
279 return fetch_cache(domain_name, CACHE_TYPE_USER, sam_entries,
283 /* Return cached entries for a domain. Return false if there are no cached
284 entries, or the cached information has expired for the domain. */
286 BOOL winbindd_fetch_group_cache(char *domain_name,
287 struct acct_info **sam_entries,
290 return fetch_cache(domain_name, CACHE_TYPE_GROUP, sam_entries,
294 static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
299 /* Create key for lookup */
300 slprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
302 /* Look up cache entry */
303 data = tdb_fetch_by_string(cache_tdb, keystr);
304 if (!data.dptr) return False;
306 DEBUG(4, ("returning cached entry for %s\\%s\n", domain, name));
308 /* Copy found entry into buffer */
309 memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
314 /* Fetch an individual user cache entry */
315 BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
316 struct winbindd_pw *pw)
320 if (lp_winbind_cache_time() == 0) return False;
322 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, user);
323 if (cache_domain_expired(domain_name, seq_num)) return False;
325 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw, sizeof(struct winbindd_pw));
328 /* Fetch an individual uid cache entry */
329 BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
330 struct winbindd_pw *pw)
335 if (lp_winbind_cache_time() == 0) return False;
337 slprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
338 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, uidstr);
339 if (cache_domain_expired(domain_name, seq_num)) return False;
341 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
344 /* Fetch an individual group cache entry. This function differs from the
345 user cache code as we need to store the group membership data. */
347 BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
348 struct winbindd_gr *gr,
349 void **extra_data, int *extra_data_len)
355 if (lp_winbind_cache_time() == 0) return False;
357 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, group);
358 if (cache_domain_expired(domain_name, seq_num)) return False;
360 /* Fetch group data */
361 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr, sizeof(struct winbindd_gr))) return False;
363 /* Fetch extra data */
364 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, group);
365 data = tdb_fetch_by_string(cache_tdb, keystr);
367 if (!data.dptr) return False;
369 /* Extra data freed when data has been sent */
370 if (extra_data) *extra_data = data.dptr;
371 if (extra_data_len) *extra_data_len = data.dsize;
377 /* Fetch an individual gid cache entry. This function differs from the
378 user cache code as we need to store the group membership data. */
380 BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
381 struct winbindd_gr *gr,
382 void **extra_data, int *extra_data_len)
389 slprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
391 if (lp_winbind_cache_time() == 0) return False;
393 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, gidstr);
394 if (cache_domain_expired(domain_name, seq_num)) return False;
396 /* Fetch group data */
397 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
398 gidstr, gr, sizeof(struct winbindd_gr))) return False;
400 /* Fetch extra data */
401 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, gidstr);
402 data = tdb_fetch_by_string(cache_tdb, keystr);
403 if (!data.dptr) return False;
405 /* Extra data freed when data has been sent */
406 if (extra_data) *extra_data = data.dptr;
407 if (extra_data_len) *extra_data_len = data.dsize;
412 /* Flush cache data - easiest to just reopen the tdb */
413 void winbindd_flush_cache(void)
415 tdb_close(cache_tdb);
416 winbindd_cache_init();