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 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
)) {
64 memcpy(&rec
, dbuf
.dptr
, sizeof(rec
));
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
));
74 rec
.seq_num
= domain_sequence_number(domain_name
);
76 tdb_store_by_string(cache_tdb
, keystr
, &rec
, sizeof(rec
));
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
));
91 static void set_cache_sequence_number(char *domain_name
, char *cache_type
, char *subkey
)
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
)
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
));
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
,
119 if (lp_winbind_cache_time() == 0) return;
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
,
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
,
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
,
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
)
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
));
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
)
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
,
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
,
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
)
243 if (lp_winbind_cache_time() == 0) return False
;
245 /* Parameter check */
246 if (!sam_entries
|| !num_sam_entries
) {
250 /* Check cache data is current */
251 if (cache_domain_expired(domain_name
,
252 get_cache_sequence_number(domain_name
, cache_type
, NULL
))) {
257 slprintf(keystr
, sizeof(keystr
), "%s CACHE DATA/%s", cache_type
,
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
));
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
,
286 return fetch_cache(domain_name
, CACHE_TYPE_USER
, sam_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
,
297 return fetch_cache(domain_name
, CACHE_TYPE_GROUP
, sam_entries
,
301 static BOOL
fetch_cache_entry(char *domain
, char *cache_type
, char *name
, void *buf
, int len
)
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
);
322 /* Fetch an individual user cache entry */
323 BOOL
winbindd_fetch_user_cache_entry(char *domain_name
, char *user
,
324 struct winbindd_pw
*pw
)
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
)
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
)
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
;
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
)
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
;
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();