link in OS2-Client-HOWTO to SWAT main page
[Samba.git] / source / nsswitch / winbindd_cache.c
blob226a96b9b50003026db9aca14de9df903be83cb7
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.0
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.
24 #include "winbindd.h"
26 #define CACHE_TYPE_USER "USR"
27 #define CACHE_TYPE_GROUP "GRP"
29 /* Initialise caching system */
31 static TDB_CONTEXT *cache_tdb;
33 struct cache_rec {
34 uint32 seq_num;
35 time_t mod_time;
38 void winbindd_cache_init(void)
40 /* Open tdb cache */
41 unlink(lock_path("winbindd_cache.tdb"));
42 if (!(cache_tdb = tdb_open(lock_path("winbindd_cache.tdb"), 0,
43 TDB_NOLOCK,
44 O_RDWR | O_CREAT, 0600))) {
45 DEBUG(0, ("Unable to open tdb cache - user and group caching "
46 "disabled\n"));
50 /* get the domain sequence number, possibly re-fetching */
51 static uint32 cached_sequence_number(char *domain_name)
53 fstring keystr;
54 TDB_DATA dbuf;
55 struct cache_rec rec;
56 time_t t = time(NULL);
58 slprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
59 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
60 dbuf = tdb_fetch_by_string(cache_tdb, keystr);
61 if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
62 goto refetch;
64 memcpy(&rec, dbuf.dptr, sizeof(rec));
65 free(dbuf.dptr);
67 if (t < (rec.mod_time + lp_winbind_cache_time())) {
68 DEBUG(4,("cached sequence number for %s is %u\n",
69 domain_name, (unsigned)rec.seq_num));
70 return rec.seq_num;
73 refetch:
74 rec.seq_num = domain_sequence_number(domain_name);
75 rec.mod_time = t;
76 tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
78 return rec.seq_num;
81 /* Check whether a seq_num for a cached item has expired */
82 static BOOL cache_domain_expired(char *domain_name, uint32 seq_num)
84 if (cached_sequence_number(domain_name) != seq_num) {
85 DEBUG(4,("seq %u for %s has expired\n", (unsigned)seq_num, domain_name));
86 return True;
88 return False;
91 static void set_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
93 fstring keystr;
94 slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
95 domain_name, cache_type, subkey?subkey:"");
96 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
97 tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
100 static uint32 get_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
102 fstring keystr;
103 uint32 seq_num;
104 slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
105 domain_name, cache_type, subkey?subkey:"");
106 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
107 seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
108 DEBUG(4,("%s is %u\n", keystr, (unsigned)seq_num));
109 return seq_num;
112 /* Fill the user or group cache with supplied data */
113 static void fill_cache(char *domain_name, char *cache_type,
114 struct acct_info *sam_entries,
115 int num_sam_entries)
117 fstring keystr;
119 if (lp_winbind_cache_time() == 0) return;
121 /* Error check */
122 if (!sam_entries || (num_sam_entries == 0)) return;
124 DEBUG(4, ("filling %s cache for domain %s with %d entries\n",
125 cache_type, domain_name, num_sam_entries));
127 /* Store data as a mega-huge chunk in the tdb */
128 slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
129 domain_name);
130 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
131 tdb_store_by_string(cache_tdb, keystr,
132 sam_entries, sizeof(struct acct_info) * num_sam_entries);
134 /* Stamp cache with current seq number */
135 set_cache_sequence_number(domain_name, cache_type, NULL);
138 /* Fill the user cache with supplied data */
140 void winbindd_fill_user_cache(char *domain_name,
141 struct acct_info *sam_entries,
142 int num_sam_entries)
144 fill_cache(domain_name, CACHE_TYPE_USER, sam_entries, num_sam_entries);
147 /* Fill the group cache with supplied data */
149 void winbindd_fill_group_cache(char *domain_name,
150 struct acct_info *sam_entries,
151 int num_sam_entries)
153 fill_cache(domain_name, CACHE_TYPE_GROUP, sam_entries, num_sam_entries);
156 static void fill_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
158 fstring keystr;
160 /* Create key for store */
161 slprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
162 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
164 DEBUG(4, ("filling cache entry %s\n", keystr));
166 /* Store it */
167 tdb_store_by_string(cache_tdb, keystr, buf, len);
170 /* Fill a user info cache entry */
171 void winbindd_fill_user_cache_entry(char *domain, char *user_name,
172 struct winbindd_pw *pw)
174 if (lp_winbind_cache_time() == 0) return;
176 fill_cache_entry(domain, CACHE_TYPE_USER, user_name, pw, sizeof(struct winbindd_pw));
177 set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
180 /* Fill a user uid cache entry */
181 void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
182 struct winbindd_pw *pw)
184 fstring uidstr;
186 if (lp_winbind_cache_time() == 0) return;
188 slprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
189 fill_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
190 set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
193 /* Fill a group info cache entry */
194 void winbindd_fill_group_cache_entry(char *domain, char *group_name,
195 struct winbindd_gr *gr, void *extra_data,
196 int extra_data_len)
198 fstring keystr;
200 if (lp_winbind_cache_time() == 0) return;
202 /* Fill group data */
203 fill_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr, sizeof(struct winbindd_gr));
205 /* Fill extra data */
206 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, group_name);
207 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
208 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
210 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
213 /* Fill a group info cache entry */
214 void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
215 struct winbindd_gr *gr, void *extra_data,
216 int extra_data_len)
218 fstring keystr;
219 fstring gidstr;
221 slprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
223 if (lp_winbind_cache_time() == 0) return;
225 /* Fill group data */
226 fill_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr, sizeof(struct winbindd_gr));
228 /* Fill extra data */
229 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, gidstr);
230 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
231 tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
233 set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
236 /* Fetch some cached user or group data */
237 static BOOL fetch_cache(char *domain_name, char *cache_type,
238 struct acct_info **sam_entries, int *num_sam_entries)
240 TDB_DATA data;
241 fstring keystr;
243 if (lp_winbind_cache_time() == 0) return False;
245 /* Parameter check */
246 if (!sam_entries || !num_sam_entries) {
247 return False;
250 /* Check cache data is current */
251 if (cache_domain_expired(domain_name,
252 get_cache_sequence_number(domain_name, cache_type, NULL))) {
253 return False;
256 /* Create key */
257 slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
258 domain_name);
259 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
261 /* Fetch cache information */
262 data = tdb_fetch_by_string(cache_tdb, keystr);
264 if (!data.dptr) return False;
266 /* Copy across cached data. We can save a memcpy() by directly
267 assigning the data.dptr to the sam_entries pointer. It will
268 be freed by the end{pw,gr}ent() function. */
270 *sam_entries = (struct acct_info *)data.dptr;
271 *num_sam_entries = data.dsize / sizeof(struct acct_info);
273 DEBUG(4, ("fetched %d cached %s entries for domain %s\n",
274 *num_sam_entries, cache_type, domain_name));
276 return True;
279 /* Return cached entries for a domain. Return false if there are no cached
280 entries, or the cached information has expired for the domain. */
282 BOOL winbindd_fetch_user_cache(char *domain_name,
283 struct acct_info **sam_entries,
284 int *num_entries)
286 return fetch_cache(domain_name, CACHE_TYPE_USER, sam_entries,
287 num_entries);
290 /* Return cached entries for a domain. Return false if there are no cached
291 entries, or the cached information has expired for the domain. */
293 BOOL winbindd_fetch_group_cache(char *domain_name,
294 struct acct_info **sam_entries,
295 int *num_entries)
297 return fetch_cache(domain_name, CACHE_TYPE_GROUP, sam_entries,
298 num_entries);
301 static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
303 TDB_DATA data;
304 fstring keystr;
306 /* Create key for lookup */
307 slprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
308 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
310 /* Look up cache entry */
311 data = tdb_fetch_by_string(cache_tdb, keystr);
312 if (!data.dptr) return False;
314 DEBUG(4, ("returning cached entry for %s\\%s\n", domain, name));
316 /* Copy found entry into buffer */
317 memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
318 free(data.dptr);
319 return True;
322 /* Fetch an individual user cache entry */
323 BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
324 struct winbindd_pw *pw)
326 uint32 seq_num;
328 if (lp_winbind_cache_time() == 0) return False;
330 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, user);
331 if (cache_domain_expired(domain_name, seq_num)) return False;
333 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw, sizeof(struct winbindd_pw));
336 /* Fetch an individual uid cache entry */
337 BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
338 struct winbindd_pw *pw)
340 fstring uidstr;
341 uint32 seq_num;
343 if (lp_winbind_cache_time() == 0) return False;
345 slprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
346 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, uidstr);
347 if (cache_domain_expired(domain_name, seq_num)) return False;
349 return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
352 /* Fetch an individual group cache entry. This function differs from the
353 user cache code as we need to store the group membership data. */
355 BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
356 struct winbindd_gr *gr,
357 void **extra_data, int *extra_data_len)
359 TDB_DATA data;
360 fstring keystr;
361 uint32 seq_num;
363 if (lp_winbind_cache_time() == 0) return False;
365 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, group);
366 if (cache_domain_expired(domain_name, seq_num)) return False;
368 /* Fetch group data */
369 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr, sizeof(struct winbindd_gr))) return False;
371 /* Fetch extra data */
372 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, group);
373 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
374 data = tdb_fetch_by_string(cache_tdb, keystr);
376 if (!data.dptr) return False;
378 /* Extra data freed when data has been sent */
379 if (extra_data) *extra_data = data.dptr;
380 if (extra_data_len) *extra_data_len = data.dsize;
382 return True;
386 /* Fetch an individual gid cache entry. This function differs from the
387 user cache code as we need to store the group membership data. */
389 BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
390 struct winbindd_gr *gr,
391 void **extra_data, int *extra_data_len)
393 TDB_DATA data;
394 fstring keystr;
395 fstring gidstr;
396 uint32 seq_num;
398 slprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
400 if (lp_winbind_cache_time() == 0) return False;
402 seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, gidstr);
403 if (cache_domain_expired(domain_name, seq_num)) return False;
405 /* Fetch group data */
406 if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
407 gidstr, gr, sizeof(struct winbindd_gr))) return False;
409 /* Fetch extra data */
410 slprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, gidstr);
411 dos_to_unix(keystr, True); /* Convert key to unix-codepage */
412 data = tdb_fetch_by_string(cache_tdb, keystr);
413 if (!data.dptr) return False;
415 /* Extra data freed when data has been sent */
416 if (extra_data) *extra_data = data.dptr;
417 if (extra_data_len) *extra_data_len = data.dsize;
419 return True;
422 /* Flush cache data - easiest to just reopen the tdb */
423 void winbindd_flush_cache(void)
425 tdb_close(cache_tdb);
426 winbindd_cache_init();