1/*
2   Unix SMB/CIFS implementation.
3
4   Winbind daemon connection manager
5
6   Copyright (C) Tim Potter 		2001
7   Copyright (C) Andrew Bartlett 	2002
8   Copyright (C) Gerald (Jerry) Carter 	2003
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25
26#include "includes.h"
27
28#define CONNCACHE_ADDR		1
29#define CONNCACHE_NAME		2
30
31/* cache entry contains either a server name **or** and IP address as
32   the key.  This means that a server could have two entries (one for each key) */
33
34struct failed_connection_cache {
35	fstring 	domain_name;
36	fstring 	controller;
37	time_t 		lookup_time;
38	NTSTATUS 	nt_status;
39	struct failed_connection_cache *prev, *next;
40};
41
42static struct failed_connection_cache *failed_connection_cache;
43
44/**********************************************************************
45 Check for a previously failed connection.
46 failed_cache_timeout is an a absolute number of seconds after which
47 we should time this out. If failed_cache_timeout == 0 then time out
48 immediately. If failed_cache_timeout == -1 then never time out.
49**********************************************************************/
50
51NTSTATUS check_negative_conn_cache_timeout( const char *domain, const char *server, unsigned int failed_cache_timeout )
52{
53	struct failed_connection_cache *fcc;
54	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
55
56	/* can't check if we don't have strings */
57
58	if ( !domain || !server )
59		return NT_STATUS_OK;
60
61	for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
62
63		if (!(strequal(domain, fcc->domain_name) && strequal(server, fcc->controller))) {
64			continue; /* no match; check the next entry */
65		}
66
67		/* we have a match so see if it is still current */
68		if (failed_cache_timeout != (unsigned int)-1) {
69			if (failed_cache_timeout == 0 ||
70					(time(NULL) - fcc->lookup_time) > (time_t)failed_cache_timeout) {
71				/* Cache entry has expired, delete it */
72
73				DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n",
74					domain, server ));
75
76				DLIST_REMOVE(failed_connection_cache, fcc);
77				SAFE_FREE(fcc);
78
79				return NT_STATUS_OK;
80			}
81		}
82
83		/* The timeout hasn't expired yet so return false */
84
85		DEBUG(10, ("check_negative_conn_cache: returning negative entry for %s, %s\n",
86			domain, server ));
87
88		result = fcc->nt_status;
89		return result;
90	}
91
92	/* end of function means no cache entry */
93	return NT_STATUS_OK;
94}
95
96NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
97{
98	return check_negative_conn_cache_timeout(domain, server, FAILED_CONNECTION_CACHE_TIMEOUT);
99}
100
101/**********************************************************************
102 Add an entry to the failed conneciton cache (aither a name of dotted
103 decimal IP
104**********************************************************************/
105
106void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result)
107{
108	struct failed_connection_cache *fcc;
109
110	SMB_ASSERT(!NT_STATUS_IS_OK(result));
111
112	/* Check we already aren't in the cache.  We always have to have
113	   a domain, but maybe not a specific DC name. */
114
115	for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
116		if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) ) {
117			DEBUG(10, ("add_failed_connection_entry: domain %s (%s) already tried and failed\n",
118				   domain, server ));
119			/* Update the failed time. */
120			fcc->lookup_time = time(NULL);
121			return;
122		}
123	}
124
125	/* Create negative lookup cache entry for this domain and controller */
126
127	if ( !(fcc = SMB_MALLOC_P(struct failed_connection_cache)) ) {
128		DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
129		return;
130	}
131
132	ZERO_STRUCTP(fcc);
133
134	fstrcpy( fcc->domain_name, domain );
135	fstrcpy( fcc->controller, server );
136	fcc->lookup_time = time(NULL);
137	fcc->nt_status = result;
138
139	DEBUG(10,("add_failed_connection_entry: added domain %s (%s) to failed conn cache\n",
140		domain, server ));
141
142	DLIST_ADD(failed_connection_cache, fcc);
143}
144
145/****************************************************************************
146****************************************************************************/
147
148void flush_negative_conn_cache( void )
149{
150	struct failed_connection_cache *fcc;
151
152	fcc = failed_connection_cache;
153
154	while (fcc) {
155		struct failed_connection_cache *fcc_next;
156
157		fcc_next = fcc->next;
158		DLIST_REMOVE(failed_connection_cache, fcc);
159		free(fcc);
160
161		fcc = fcc_next;
162	}
163
164}
165
166/****************************************************************************
167 Remove all negative entries for a domain. Used when going to online state in
168 winbindd.
169****************************************************************************/
170
171void flush_negative_conn_cache_for_domain(const char *domain)
172{
173	struct failed_connection_cache *fcc;
174
175	fcc = failed_connection_cache;
176
177	while (fcc) {
178		struct failed_connection_cache *fcc_next;
179
180		fcc_next = fcc->next;
181
182		if (strequal(fcc->domain_name, domain)) {
183			DEBUG(10,("flush_negative_conn_cache_for_domain: removed server %s "
184				" from failed cache for domain %s\n",
185				fcc->controller, domain));
186			DLIST_REMOVE(failed_connection_cache, fcc);
187			free(fcc);
188		}
189
190		fcc = fcc_next;
191	}
192}
193