Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : NetBIOS name cache module on top of gencache mechanism.
5 :
6 : Copyright (C) Tim Potter 2002
7 : Copyright (C) Rafal Szczesniak 2002
8 : Copyright (C) Jeremy Allison 2007
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 3 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, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "lib/gencache.h"
26 : #include "libsmb/namequery.h"
27 :
28 : #define IPSTR_LIST_SEP ","
29 : #define IPSTR_LIST_CHAR ','
30 :
31 : /**
32 : * Allocate and initialise an ipstr list using samba_sockaddr ip adresses
33 : * passed as arguments.
34 : *
35 : * @param ctx TALLOC_CTX to use
36 : * @param ip_list array of ip addresses to place in the list
37 : * @param ip_count number of addresses stored in ip_list
38 : * @return pointer to allocated ip string
39 : **/
40 :
41 156 : static char *ipstr_list_make_sa(TALLOC_CTX *ctx,
42 : const struct samba_sockaddr *sa_list,
43 : size_t ip_count)
44 : {
45 156 : char *ipstr_list = NULL;
46 : size_t i;
47 :
48 : /* arguments checking */
49 156 : if (sa_list == NULL) {
50 0 : return NULL;
51 : }
52 :
53 : /* process ip addresses given as arguments */
54 725 : for (i = 0; i < ip_count; i++) {
55 : char addr_buf[INET6_ADDRSTRLEN];
56 290 : char *new_str = NULL;
57 :
58 290 : print_sockaddr(addr_buf,
59 : sizeof(addr_buf),
60 290 : &sa_list[i].u.ss);
61 :
62 290 : if (sa_list[i].u.ss.ss_family == AF_INET) {
63 : /* IPv4 - port no longer used, store 0 */
64 156 : new_str = talloc_asprintf(ctx,
65 : "%s:%d",
66 : addr_buf,
67 : 0);
68 : } else {
69 : /* IPv6 - port no longer used, store 0 */
70 134 : new_str = talloc_asprintf(ctx,
71 : "[%s]:%d",
72 : addr_buf,
73 : 0);
74 : }
75 290 : if (new_str == NULL) {
76 0 : TALLOC_FREE(ipstr_list);
77 0 : return NULL;
78 : }
79 :
80 290 : if (ipstr_list == NULL) {
81 : /* First ip address. */
82 156 : ipstr_list = new_str;
83 : } else {
84 : /*
85 : * Append the separator "," and then the new
86 : * ip address to the existing list.
87 : *
88 : * The efficiency here is horrible, but
89 : * ip_count should be small enough we can
90 : * live with it.
91 : */
92 134 : char *tmp = talloc_asprintf(ctx,
93 : "%s%s%s",
94 : ipstr_list,
95 : IPSTR_LIST_SEP,
96 : new_str);
97 134 : if (tmp == NULL) {
98 0 : TALLOC_FREE(new_str);
99 0 : TALLOC_FREE(ipstr_list);
100 0 : return NULL;
101 : }
102 134 : TALLOC_FREE(new_str);
103 134 : TALLOC_FREE(ipstr_list);
104 134 : ipstr_list = tmp;
105 : }
106 : }
107 :
108 156 : return ipstr_list;
109 : }
110 :
111 : /**
112 : * Parse given ip string list into array of ip addresses
113 : * (as ip_service structures)
114 : * e.g. [IPv6]:port,192.168.1.100:389,192.168.1.78, ...
115 : *
116 : * @param ipstr ip string list to be parsed
117 : * @param ip_list pointer to array of ip addresses which is
118 : * talloced by this function and must be freed by caller
119 : * @return number of successfully parsed addresses
120 : **/
121 :
122 1639 : static int ipstr_list_parse(TALLOC_CTX *ctx,
123 : const char *ipstr_list,
124 : struct samba_sockaddr **sa_list_out)
125 : {
126 1639 : TALLOC_CTX *frame = talloc_stackframe();
127 1639 : struct samba_sockaddr *sa_list = NULL;
128 1639 : char *token_str = NULL;
129 : size_t i, count;
130 : size_t array_size;
131 :
132 1639 : *sa_list_out = NULL;
133 :
134 1639 : array_size = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1;
135 1639 : sa_list = talloc_zero_array(frame,
136 : struct samba_sockaddr,
137 : array_size);
138 1639 : if (sa_list == NULL) {
139 0 : TALLOC_FREE(frame);
140 0 : return 0;
141 : }
142 :
143 1639 : count = 0;
144 5964 : for (i=0; next_token_talloc(frame, &ipstr_list, &token_str,
145 3146 : IPSTR_LIST_SEP); i++ ) {
146 : bool ok;
147 3146 : char *s = token_str;
148 3146 : char *p = strrchr(token_str, ':');
149 : struct sockaddr_storage ss;
150 :
151 : /* Ensure we don't overrun. */
152 3146 : if (count >= array_size) {
153 0 : break;
154 : }
155 :
156 3146 : if (p) {
157 3146 : *p = 0;
158 : /* We now ignore the port. */
159 : }
160 :
161 : /* convert single token to ip address */
162 3146 : if (token_str[0] == '[') {
163 : /* IPv6 address. */
164 1507 : s++;
165 1507 : p = strchr(token_str, ']');
166 1507 : if (!p) {
167 0 : continue;
168 : }
169 1507 : *p = '\0';
170 : }
171 3146 : ok = interpret_string_addr(&ss, s, AI_NUMERICHOST);
172 3146 : if (!ok) {
173 0 : continue;
174 : }
175 3146 : ok = sockaddr_storage_to_samba_sockaddr(&sa_list[count],
176 : &ss);
177 3146 : if (!ok) {
178 0 : continue;
179 : }
180 3146 : count++;
181 : }
182 1639 : if (count > 0) {
183 1639 : *sa_list_out = talloc_move(ctx, &sa_list);
184 : }
185 1639 : TALLOC_FREE(frame);
186 1639 : return count;
187 : }
188 :
189 : #define NBTKEY_FMT "NBT/%s#%02X"
190 :
191 : /**
192 : * Generates a key for netbios name lookups on basis of
193 : * netbios name and type.
194 : * The caller must free returned key string when finished.
195 : *
196 : * @param name netbios name string (case insensitive)
197 : * @param name_type netbios type of the name being looked up
198 : *
199 : * @return string consisted of uppercased name and appended
200 : * type number
201 : */
202 :
203 1949 : static char *namecache_key(TALLOC_CTX *ctx,
204 : const char *name,
205 : int name_type)
206 : {
207 1949 : return talloc_asprintf_strupper_m(ctx,
208 : NBTKEY_FMT,
209 : name,
210 : name_type);
211 : }
212 :
213 : /**
214 : * Store a name(s) in the name cache - samba_sockaddr version.
215 : *
216 : * @param name netbios names array
217 : * @param name_type integer netbios name type
218 : * @param num_names number of names being stored
219 : * @param ip_list array of in_addr structures containing
220 : * ip addresses being stored
221 : **/
222 :
223 172 : bool namecache_store(const char *name,
224 : int name_type,
225 : size_t num_names,
226 : struct samba_sockaddr *sa_list)
227 : {
228 : time_t expiry;
229 172 : char *key = NULL;
230 172 : char *value_string = NULL;
231 : size_t i;
232 172 : bool ret = false;
233 172 : TALLOC_CTX *frame = talloc_stackframe();
234 :
235 172 : if (name_type > 255) {
236 : /* Don't store non-real name types. */
237 16 : goto out;
238 : }
239 :
240 156 : if ( DEBUGLEVEL >= 5 ) {
241 0 : char *addr = NULL;
242 :
243 0 : DBG_INFO("storing %zu address%s for %s#%02x: ",
244 : num_names, num_names == 1 ? "": "es", name, name_type);
245 :
246 0 : for (i = 0; i < num_names; i++) {
247 0 : addr = print_canonical_sockaddr(frame,
248 0 : &sa_list[i].u.ss);
249 0 : if (!addr) {
250 0 : continue;
251 : }
252 0 : DEBUGADD(5, ("%s%s", addr,
253 : (i == (num_names - 1) ? "" : ",")));
254 :
255 : }
256 0 : DEBUGADD(5, ("\n"));
257 : }
258 :
259 156 : key = namecache_key(frame, name, name_type);
260 156 : if (!key) {
261 0 : goto out;
262 : }
263 :
264 156 : expiry = time(NULL) + lp_name_cache_timeout();
265 :
266 : /*
267 : * Generate string representation of ip addresses list
268 : */
269 156 : value_string = ipstr_list_make_sa(frame, sa_list, num_names);
270 156 : if (value_string == NULL) {
271 0 : goto out;
272 : }
273 :
274 : /* set the entry */
275 156 : ret = gencache_set(key, value_string, expiry);
276 :
277 172 : out:
278 :
279 172 : TALLOC_FREE(key);
280 172 : TALLOC_FREE(value_string);
281 172 : TALLOC_FREE(frame);
282 172 : return ret;
283 : }
284 :
285 : /**
286 : * Look up a name in the cache.
287 : *
288 : * @param name netbios name to look up for
289 : * @param name_type netbios name type of @param name
290 : * @param ip_list talloced list of IP addresses if found in the cache,
291 : * NULL otherwise
292 : * @param num_names number of entries found
293 : *
294 : * @return true upon successful fetch or
295 : * false if name isn't found in the cache or has expired
296 : **/
297 :
298 1803 : bool namecache_fetch(TALLOC_CTX *ctx,
299 : const char *name,
300 : int name_type,
301 : struct samba_sockaddr **sa_list,
302 : size_t *num_names)
303 : {
304 : char *key, *value;
305 : time_t timeout;
306 :
307 1803 : if (name_type > 255) {
308 16 : return false; /* Don't fetch non-real name types. */
309 : }
310 :
311 1787 : *num_names = 0;
312 :
313 : /*
314 : * Use gencache interface - lookup the key
315 : */
316 1787 : key = namecache_key(talloc_tos(), name, name_type);
317 1787 : if (!key) {
318 0 : return false;
319 : }
320 :
321 1787 : if (!gencache_get(key, talloc_tos(), &value, &timeout)) {
322 148 : DBG_INFO("no entry for %s#%02X found.\n", name, name_type);
323 148 : TALLOC_FREE(key);
324 148 : return false;
325 : }
326 :
327 1639 : DBG_INFO("name %s#%02X found.\n", name, name_type);
328 :
329 : /*
330 : * Split up the stored value into the list of IP adresses
331 : */
332 1639 : *num_names = ipstr_list_parse(ctx, value, sa_list);
333 :
334 1639 : TALLOC_FREE(key);
335 1639 : TALLOC_FREE(value);
336 :
337 1639 : return *num_names > 0; /* true only if some ip has been fetched */
338 : }
339 :
340 : /**
341 : * Remove a namecache entry. Needed for site support.
342 : *
343 : **/
344 :
345 6 : bool namecache_delete(const char *name, int name_type)
346 : {
347 : bool ret;
348 : char *key;
349 :
350 6 : if (name_type > 255) {
351 0 : return false; /* Don't fetch non-real name types. */
352 : }
353 :
354 6 : key = namecache_key(talloc_tos(), name, name_type);
355 6 : if (!key) {
356 0 : return false;
357 : }
358 6 : ret = gencache_del(key);
359 6 : TALLOC_FREE(key);
360 6 : return ret;
361 : }
362 :
363 : /**
364 : * Delete single namecache entry. Look at the
365 : * gencache_iterate definition.
366 : *
367 : **/
368 :
369 0 : static void flush_netbios_name(const char *key,
370 : const char *value,
371 : time_t timeout,
372 : void *dptr)
373 : {
374 0 : gencache_del(key);
375 0 : DBG_INFO("Deleting entry %s\n", key);
376 0 : }
377 :
378 : /**
379 : * Flush all names from the name cache.
380 : * It's done by gencache_iterate()
381 : *
382 : * @return true upon successful deletion or
383 : * false in case of an error
384 : **/
385 :
386 0 : void namecache_flush(void)
387 : {
388 : /*
389 : * iterate through each NBT cache's entry and flush it
390 : * by flush_netbios_name function
391 : */
392 0 : gencache_iterate(flush_netbios_name, NULL, "NBT/*");
393 0 : DBG_INFO("Namecache flushed\n");
394 0 : }
395 :
396 : /* Construct a name status record key. */
397 :
398 3 : static char *namecache_status_record_key(TALLOC_CTX *ctx,
399 : const char *name,
400 : int name_type1,
401 : int name_type2,
402 : const struct sockaddr_storage *keyip)
403 : {
404 : char addr[INET6_ADDRSTRLEN];
405 :
406 3 : print_sockaddr(addr, sizeof(addr), keyip);
407 3 : return talloc_asprintf_strupper_m(ctx,
408 : "NBT/%s#%02X.%02X.%s",
409 : name,
410 : name_type1,
411 : name_type2,
412 : addr);
413 : }
414 :
415 : /* Store a name status record. */
416 :
417 0 : bool namecache_status_store(const char *keyname, int keyname_type,
418 : int name_type, const struct sockaddr_storage *keyip,
419 : const char *srvname)
420 : {
421 : char *key;
422 : time_t expiry;
423 : bool ret;
424 :
425 0 : key = namecache_status_record_key(talloc_tos(),
426 : keyname,
427 : keyname_type,
428 : name_type,
429 : keyip);
430 0 : if (!key)
431 0 : return false;
432 :
433 0 : expiry = time(NULL) + lp_name_cache_timeout();
434 0 : ret = gencache_set(key, srvname, expiry);
435 :
436 0 : if (ret) {
437 0 : DBG_INFO("entry %s -> %s\n", key, srvname);
438 : } else {
439 0 : DBG_INFO("entry %s store failed.\n", key);
440 : }
441 :
442 0 : TALLOC_FREE(key);
443 0 : return ret;
444 : }
445 :
446 : /* Fetch a name status record. */
447 :
448 3 : bool namecache_status_fetch(const char *keyname,
449 : int keyname_type,
450 : int name_type,
451 : const struct sockaddr_storage *keyip,
452 : char *srvname_out)
453 : {
454 3 : char *key = NULL;
455 3 : char *value = NULL;
456 : time_t timeout;
457 :
458 3 : key = namecache_status_record_key(talloc_tos(),
459 : keyname,
460 : keyname_type,
461 : name_type,
462 : keyip);
463 3 : if (!key)
464 0 : return false;
465 :
466 3 : if (!gencache_get(key, talloc_tos(), &value, &timeout)) {
467 3 : DBG_INFO("no entry for %s found.\n", key);
468 3 : TALLOC_FREE(key);
469 3 : return false;
470 : } else {
471 0 : DBG_INFO("key %s -> %s\n", key, value);
472 : }
473 :
474 0 : strlcpy(srvname_out, value, 16);
475 0 : TALLOC_FREE(key);
476 0 : TALLOC_FREE(value);
477 0 : return true;
478 : }
|