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