Line data Source code
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 : Copyright (C) Marc VanHeyningen 2008
10 : Copyright (C) Volker Lendecke 2009
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 :
27 : #include "includes.h"
28 : #include "lib/gencache.h"
29 :
30 : /**
31 : * @file
32 : * Negative connection cache implemented in terms of gencache API
33 : *
34 : * The negative connection cache stores names of servers which have
35 : * been unresponsive so that we don't waste time repeatedly trying
36 : * to contact them. It used to use an in-memory linked list, but
37 : * this limited its utility to a single process
38 : */
39 :
40 :
41 : /**
42 : * Marshalls the domain and server name into the key for the gencache
43 : * record
44 : *
45 : * @param[in] domain required
46 : * @param[in] server may be a FQDN or an IP address
47 : * @return the resulting string, which the caller is responsible for
48 : * SAFE_FREE()ing
49 : * @retval NULL returned on error
50 : */
51 2431 : static char *negative_conn_cache_keystr(const char *domain, const char *server)
52 : {
53 2431 : char *keystr = NULL;
54 :
55 2431 : if (domain == NULL) {
56 0 : return NULL;
57 : }
58 2431 : if (server == NULL)
59 0 : server = "";
60 :
61 2431 : keystr = talloc_asprintf(talloc_tos(), "NEG_CONN_CACHE/%s,%s",
62 : domain, server);
63 2431 : if (keystr == NULL) {
64 0 : DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
65 : }
66 :
67 2431 : return keystr;
68 : }
69 :
70 : /**
71 : * Marshalls the NT status into a printable value field for the gencache
72 : * record
73 : *
74 : * @param[in] status
75 : * @return the resulting string, which the caller is responsible for
76 : * SAFE_FREE()ing
77 : * @retval NULL returned on error
78 : */
79 0 : static char *negative_conn_cache_valuestr(NTSTATUS status)
80 : {
81 0 : char *valuestr = NULL;
82 :
83 0 : valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
84 0 : if (valuestr == NULL) {
85 0 : DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
86 : }
87 :
88 0 : return valuestr;
89 : }
90 :
91 : /**
92 : * Un-marshalls the NT status from a printable field for the gencache
93 : * record
94 : *
95 : * @param[in] value The value field from the record
96 : * @return the decoded NT status
97 : * @retval NT_STATUS_OK returned on error
98 : */
99 0 : static NTSTATUS negative_conn_cache_valuedecode(const char *value)
100 : {
101 0 : unsigned int v = NT_STATUS_V(NT_STATUS_INTERNAL_ERROR);
102 :
103 0 : if (value == NULL) {
104 0 : return NT_STATUS_INTERNAL_ERROR;
105 : }
106 0 : if (sscanf(value, "%x", &v) != 1) {
107 0 : DEBUG(0, ("negative_conn_cache_valuedecode: unable to parse "
108 : "value field '%s'\n", value));
109 : }
110 0 : return NT_STATUS(v);
111 : }
112 :
113 : /**
114 : * Function passed to gencache_iterate to remove any matching items
115 : * from the list
116 : *
117 : * @param[in] key Key to the record found and to be deleted
118 : * @param[in] value Value to the record (ignored)
119 : * @param[in] timeout Timeout remaining for the record (ignored)
120 : * @param[in] dptr Handle for passing additional data (ignored)
121 : */
122 0 : static void delete_matches(const char *key, const char *value,
123 : time_t timeout, void *dptr)
124 : {
125 0 : gencache_del(key);
126 0 : }
127 :
128 :
129 : /**
130 : * Checks for a given domain/server record in the negative cache
131 : *
132 : * @param[in] domain
133 : * @param[in] server may be either a FQDN or an IP address
134 : * @return The cached failure status
135 : * @retval NT_STATUS_OK returned if no record is found or an error occurs
136 : */
137 2339 : NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
138 : {
139 2339 : NTSTATUS result = NT_STATUS_OK;
140 2339 : char *key = NULL;
141 2339 : char *value = NULL;
142 :
143 2339 : key = negative_conn_cache_keystr(domain, server);
144 2339 : if (key == NULL)
145 0 : goto done;
146 :
147 2339 : if (gencache_get(key, talloc_tos(), &value, NULL))
148 0 : result = negative_conn_cache_valuedecode(value);
149 2339 : done:
150 2339 : DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
151 : "server %s\n", NT_STATUS_V(result), domain, server));
152 2339 : TALLOC_FREE(key);
153 2339 : TALLOC_FREE(value);
154 2339 : return result;
155 : }
156 :
157 : /**
158 : * Add an entry to the failed connection cache
159 : *
160 : * @param[in] domain
161 : * @param[in] server may be a FQDN or an IP addr in printable form
162 : * @param[in] result error to cache; must not be NT_STATUS_OK
163 : */
164 0 : void add_failed_connection_entry(const char *domain, const char *server,
165 : NTSTATUS result)
166 : {
167 0 : char *key = NULL;
168 0 : char *value = NULL;
169 :
170 0 : if (NT_STATUS_IS_OK(result)) {
171 : /* Nothing failed here */
172 0 : return;
173 : }
174 :
175 0 : key = negative_conn_cache_keystr(domain, server);
176 0 : if (key == NULL) {
177 0 : DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
178 0 : goto done;
179 : }
180 :
181 0 : value = negative_conn_cache_valuestr(result);
182 0 : if (value == NULL) {
183 0 : DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
184 0 : goto done;
185 : }
186 :
187 0 : if (gencache_set(key, value,
188 0 : time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT))
189 0 : DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
190 : "to failed conn cache\n", domain, server ));
191 : else
192 0 : DEBUG(1,("add_failed_connection_entry: failed to add "
193 : "domain %s (%s) to failed conn cache\n",
194 : domain, server));
195 :
196 0 : done:
197 0 : TALLOC_FREE(key);
198 0 : TALLOC_FREE(value);
199 0 : return;
200 : }
201 :
202 : /**
203 : * Deletes all records for a specified domain from the negative connection
204 : * cache
205 : *
206 : * @param[in] domain String to match against domain portion of keys, or "*"
207 : * to match all domains
208 : */
209 92 : void flush_negative_conn_cache_for_domain(const char *domain)
210 : {
211 92 : char *key_pattern = NULL;
212 :
213 92 : key_pattern = negative_conn_cache_keystr(domain,"*");
214 92 : if (key_pattern == NULL) {
215 0 : DEBUG(0, ("flush_negative_conn_cache_for_domain: "
216 : "key creation error\n"));
217 0 : goto done;
218 : }
219 :
220 92 : gencache_iterate(delete_matches, NULL, key_pattern);
221 92 : DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
222 : domain));
223 :
224 92 : done:
225 92 : TALLOC_FREE(key_pattern);
226 92 : return;
227 : }
|