1/*
2   Unix SMB/CIFS implementation.
3
4   Trusted domain names cache on top of gencache.
5
6   Copyright (C) Rafal Szczesniak	2002
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#include "includes.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_ALL	/* there's no proper class yet */
27
28#define TDOMKEY_FMT  "TDOM/%s"
29#define TDOMTSKEY    "TDOMCACHE/TIMESTAMP"
30
31
32/**
33 * @file trustdom_cache.c
34 *
35 * Implementation of trusted domain names cache useful when
36 * samba acts as domain member server. In such case, caching
37 * domain names currently trusted gives a performance gain
38 * because there's no need to query PDC each time we need
39 * list of trusted domains
40 **/
41
42
43/**
44 * Initialise trustdom name caching system. Call gencache
45 * initialisation routine to perform necessary activities.
46 *
47 * @return true upon successful cache initialisation or
48 *         false if cache init failed
49 **/
50
51BOOL trustdom_cache_enable(void)
52{
53	/* Init trustdom cache by calling gencache initialisation */
54	if (!gencache_init()) {
55		DEBUG(2, ("trustdomcache_enable: Couldn't initialise trustdom cache on top of gencache.\n"));
56		return False;
57	}
58
59	return True;
60}
61
62
63/**
64 * Shutdown trustdom name caching system. Calls gencache
65 * shutdown function.
66 *
67 * @return true upon successful cache close or
68 *         false if it failed
69 **/
70
71BOOL trustdom_cache_shutdown(void)
72{
73	/* Close trustdom cache by calling gencache shutdown */
74	if (!gencache_shutdown()) {
75		DEBUG(2, ("trustdomcache_shutdown: Couldn't shutdown trustdom cache on top of gencache.\n"));
76		return False;
77	}
78
79	return True;
80}
81
82
83/**
84 * Form up trustdom name key. It is based only
85 * on domain name now.
86 *
87 * @param name trusted domain name
88 * @return cache key for use in gencache mechanism
89 **/
90
91static char* trustdom_cache_key(const char* name)
92{
93	char* keystr = NULL;
94	asprintf(&keystr, TDOMKEY_FMT, strupper_static(name));
95
96	return keystr;
97}
98
99
100/**
101 * Store trusted domain in gencache as the domain name (key)
102 * and ip address of domain controller (value)
103 *
104 * @param name trusted domain name
105 * @param alt_name alternative trusted domain name (used in ADS domains)
106 * @param sid trusted domain's SID
107 * @param timeout cache entry expiration time
108 * @return true upon successful value storing or
109 *         false if store attempt failed
110 **/
111
112BOOL trustdom_cache_store(char* name, char* alt_name, const DOM_SID *sid,
113                          time_t timeout)
114{
115	char *key, *alt_key;
116	fstring sid_string;
117	BOOL ret;
118
119	/*
120	 * we use gecache call to avoid annoying debug messages
121	 * about initialised trustdom
122	 */
123	if (!gencache_init())
124		return False;
125
126	DEBUG(5, ("trustdom_store: storing SID %s of domain %s\n",
127	          sid_string_static(sid), name));
128
129	key = trustdom_cache_key(name);
130	alt_key = alt_name ? trustdom_cache_key(alt_name) : NULL;
131
132	/* Generate string representation domain SID */
133	sid_to_string(sid_string, sid);
134
135	/*
136	 * try to put the names in the cache
137	 */
138	if (alt_key) {
139		ret = gencache_set(alt_key, sid_string, timeout);
140		if ( ret ) {
141			ret = gencache_set(key, sid_string, timeout);
142		}
143		SAFE_FREE(alt_key);
144		SAFE_FREE(key);
145		return ret;
146	}
147
148	ret = gencache_set(key, sid_string, timeout);
149	SAFE_FREE(key);
150	return ret;
151}
152
153
154/**
155 * Fetch trusted domain's dc from the gencache.
156 * This routine can also be used to check whether given
157 * domain is currently trusted one.
158 *
159 * @param name trusted domain name
160 * @param sid trusted domain's SID to be returned
161 * @return true if entry is found or
162 *         false if has expired/doesn't exist
163 **/
164
165BOOL trustdom_cache_fetch(const char* name, DOM_SID* sid)
166{
167	char *key = NULL, *value = NULL;
168	time_t timeout;
169
170	/* init the cache */
171	if (!gencache_init())
172		return False;
173
174	/* exit now if null pointers were passed as they're required further */
175	if (!sid)
176		return False;
177
178	/* prepare a key and get the value */
179	key = trustdom_cache_key(name);
180	if (!key)
181		return False;
182
183	if (!gencache_get(key, &value, &timeout)) {
184		DEBUG(5, ("no entry for trusted domain %s found.\n", name));
185		SAFE_FREE(key);
186		SAFE_FREE(value);
187		return False;
188	} else {
189		SAFE_FREE(key);
190		DEBUG(5, ("trusted domain %s found (%s)\n", name, value));
191	}
192
193	/* convert ip string representation into in_addr structure */
194	if(! string_to_sid(sid, value)) {
195		sid = NULL;
196		SAFE_FREE(value);
197		return False;
198	}
199
200	SAFE_FREE(value);
201	return True;
202}
203
204
205/*******************************************************************
206 fetch the timestamp from the last update
207*******************************************************************/
208
209uint32 trustdom_cache_fetch_timestamp( void )
210{
211	char *value = NULL;
212	time_t timeout;
213	uint32 timestamp;
214
215	/* init the cache */
216	if (!gencache_init())
217		return False;
218
219	if (!gencache_get(TDOMTSKEY, &value, &timeout)) {
220		DEBUG(5, ("no timestamp for trusted domain cache located.\n"));
221		SAFE_FREE(value);
222		return 0;
223	}
224
225	timestamp = atoi(value);
226
227	SAFE_FREE(value);
228	return timestamp;
229}
230
231/*******************************************************************
232 store the timestamp from the last update
233*******************************************************************/
234
235BOOL trustdom_cache_store_timestamp( uint32 t, time_t timeout )
236{
237	fstring value;
238
239	/* init the cache */
240	if (!gencache_init())
241		return False;
242
243	fstr_sprintf(value, "%d", t );
244
245	if (!gencache_set(TDOMTSKEY, value, timeout)) {
246		DEBUG(5, ("failed to set timestamp for trustdom_cache\n"));
247		return False;
248	}
249
250	return True;
251}
252
253
254/*******************************************************************
255 lock the timestamp entry in the trustdom_cache
256*******************************************************************/
257
258BOOL trustdom_cache_lock_timestamp( void )
259{
260	return gencache_lock_entry( TDOMTSKEY ) != -1;
261}
262
263/*******************************************************************
264 unlock the timestamp entry in the trustdom_cache
265*******************************************************************/
266
267void trustdom_cache_unlock_timestamp( void )
268{
269	gencache_unlock_entry( TDOMTSKEY );
270}
271
272/**
273 * Delete single trustdom entry. Look at the
274 * gencache_iterate definition.
275 *
276 **/
277
278static void flush_trustdom_name(const char* key, const char *value, time_t timeout, void* dptr)
279{
280	gencache_del(key);
281	DEBUG(5, ("Deleting entry %s\n", key));
282}
283
284
285/**
286 * Flush all the trusted domains entries from the cache.
287 **/
288
289void trustdom_cache_flush(void)
290{
291	if (!gencache_init())
292		return;
293
294	/*
295	 * iterate through each TDOM cache's entry and flush it
296	 * by flush_trustdom_name function
297	 */
298	gencache_iterate(flush_trustdom_name, NULL, trustdom_cache_key("*"));
299	DEBUG(5, ("Trusted domains cache flushed\n"));
300}
301
302/********************************************************************
303 update the trustdom_cache if needed
304********************************************************************/
305#define TRUSTDOM_UPDATE_INTERVAL	600
306
307void update_trustdom_cache( void )
308{
309	char **domain_names;
310	DOM_SID *dom_sids;
311	uint32 num_domains;
312	uint32 last_check;
313	int time_diff;
314	TALLOC_CTX *mem_ctx = NULL;
315	time_t now = time(NULL);
316	int i;
317
318	/* get the timestamp.  We have to initialise it if the last timestamp == 0 */
319
320	if ( (last_check = trustdom_cache_fetch_timestamp()) == 0 )
321		trustdom_cache_store_timestamp(0, now+TRUSTDOM_UPDATE_INTERVAL);
322
323	time_diff = now - last_check;
324
325	if ( (time_diff > 0) && (time_diff < TRUSTDOM_UPDATE_INTERVAL) ) {
326		DEBUG(10,("update_trustdom_cache: not time to update trustdom_cache yet\n"));
327		return;
328	}
329
330	/* lock the timestamp */
331	if ( !trustdom_cache_lock_timestamp() )
332		return;
333
334	if ( !(mem_ctx = talloc_init("update_trustdom_cache")) ) {
335		DEBUG(0,("update_trustdom_cache: talloc_init() failed!\n"));
336		goto done;
337	}
338
339	/* get the domains and store them */
340
341	if ( enumerate_domain_trusts(mem_ctx, lp_workgroup(), &domain_names,
342		&num_domains, &dom_sids) )
343	{
344		for ( i=0; i<num_domains; i++ ) {
345			trustdom_cache_store( domain_names[i], NULL, &dom_sids[i],
346				now+TRUSTDOM_UPDATE_INTERVAL);
347		}
348
349		trustdom_cache_store_timestamp( now, now+TRUSTDOM_UPDATE_INTERVAL );
350	}
351
352done:
353	/* unlock and we're done */
354	trustdom_cache_unlock_timestamp();
355
356	talloc_destroy( mem_ctx );
357
358	return;
359}
360