LCOV - code coverage report
Current view: top level - source3/libsmb - namecache.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 118 155 76.1 %
Date: 2021-09-23 10:06:22 Functions: 9 11 81.8 %

          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         424 : static char *ipstr_list_make_sa(TALLOC_CTX *ctx,
      42             :                         const struct samba_sockaddr *sa_list,
      43             :                         size_t ip_count)
      44             : {
      45         424 :         char *ipstr_list = NULL;
      46             :         size_t i;
      47             : 
      48             :         /* arguments checking */
      49         424 :         if (sa_list == NULL) {
      50           0 :                 return NULL;
      51             :         }
      52             : 
      53             :         /* process ip addresses given as arguments */
      54        2182 :         for (i = 0; i < ip_count; i++) {
      55             :                 char addr_buf[INET6_ADDRSTRLEN];
      56         776 :                 char *new_str = NULL;
      57             : 
      58         776 :                 print_sockaddr(addr_buf,
      59             :                                 sizeof(addr_buf),
      60         776 :                                 &sa_list[i].u.ss);
      61             : 
      62         776 :                 if (sa_list[i].u.ss.ss_family == AF_INET) {
      63             :                         /* IPv4 - port no longer used, store 0 */
      64         426 :                         new_str = talloc_asprintf(ctx,
      65             :                                                 "%s:%d",
      66             :                                                 addr_buf,
      67             :                                                 0);
      68             :                 } else {
      69             :                         /* IPv6 - port no longer used, store 0 */
      70         350 :                         new_str = talloc_asprintf(ctx,
      71             :                                                 "[%s]:%d",
      72             :                                                 addr_buf,
      73             :                                                 0);
      74             :                 }
      75         776 :                 if (new_str == NULL) {
      76           0 :                         TALLOC_FREE(ipstr_list);
      77           0 :                         return NULL;
      78             :                 }
      79             : 
      80         776 :                 if (ipstr_list == NULL) {
      81             :                         /* First ip address. */
      82         424 :                         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         352 :                         char *tmp = talloc_asprintf(ctx,
      93             :                                                 "%s%s%s",
      94             :                                                 ipstr_list,
      95             :                                                 IPSTR_LIST_SEP,
      96             :                                                 new_str);
      97         352 :                         if (tmp == NULL) {
      98           0 :                                 TALLOC_FREE(new_str);
      99           0 :                                 TALLOC_FREE(ipstr_list);
     100           0 :                                 return NULL;
     101             :                         }
     102         352 :                         TALLOC_FREE(new_str);
     103         352 :                         TALLOC_FREE(ipstr_list);
     104         352 :                         ipstr_list = tmp;
     105             :                 }
     106             :         }
     107             : 
     108         424 :         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        8200 : static int ipstr_list_parse(TALLOC_CTX *ctx,
     123             :                         const char *ipstr_list,
     124             :                         struct samba_sockaddr **sa_list_out)
     125             : {
     126        8200 :         TALLOC_CTX *frame = talloc_stackframe();
     127        8200 :         struct samba_sockaddr *sa_list = NULL;
     128        8200 :         char *token_str = NULL;
     129             :         size_t i, count;
     130             :         size_t array_size;
     131             : 
     132        8200 :         *sa_list_out = NULL;
     133             : 
     134        8200 :         array_size = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1;
     135        8200 :         sa_list = talloc_zero_array(frame,
     136             :                                 struct samba_sockaddr,
     137             :                                 array_size);
     138        8200 :         if (sa_list == NULL) {
     139           0 :                 TALLOC_FREE(frame);
     140           0 :                 return 0;
     141             :         }
     142             : 
     143        8200 :         count = 0;
     144       31625 :         for (i=0; next_token_talloc(frame, &ipstr_list, &token_str,
     145       16227 :                                 IPSTR_LIST_SEP); i++ ) {
     146             :                 bool ok;
     147       16227 :                 char *s = token_str;
     148       16227 :                 char *p = strrchr(token_str, ':');
     149             :                 struct sockaddr_storage ss;
     150             : 
     151             :                 /* Ensure we don't overrun. */
     152       16227 :                 if (count >= array_size) {
     153           0 :                         break;
     154             :                 }
     155             : 
     156       16227 :                 if (p) {
     157       16227 :                         *p = 0;
     158             :                         /* We now ignore the port. */
     159             :                 }
     160             : 
     161             :                 /* convert single token to ip address */
     162       16227 :                 if (token_str[0] == '[') {
     163             :                         /* IPv6 address. */
     164        8023 :                         s++;
     165        8023 :                         p = strchr(token_str, ']');
     166        8023 :                         if (!p) {
     167           0 :                                 continue;
     168             :                         }
     169        8023 :                         *p = '\0';
     170             :                 }
     171       16227 :                 ok = interpret_string_addr(&ss, s, AI_NUMERICHOST);
     172       16227 :                 if (!ok) {
     173           0 :                         continue;
     174             :                 }
     175       16227 :                 ok = sockaddr_storage_to_samba_sockaddr(&sa_list[count],
     176             :                                                         &ss);
     177       16227 :                 if (!ok) {
     178           0 :                         continue;
     179             :                 }
     180       16227 :                 count++;
     181             :         }
     182        8200 :         if (count > 0) {
     183        8200 :                 *sa_list_out = talloc_move(ctx, &sa_list);
     184             :         }
     185        8200 :         TALLOC_FREE(frame);
     186        8200 :         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        9064 : static char *namecache_key(TALLOC_CTX *ctx,
     204             :                            const char *name,
     205             :                            int name_type)
     206             : {
     207        9064 :         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         844 : 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         844 :         char *key = NULL;
     230         844 :         char *value_string = NULL;
     231             :         size_t i;
     232         844 :         bool ret = false;
     233         844 :         TALLOC_CTX *frame = talloc_stackframe();
     234             : 
     235         844 :         if (name_type > 255) {
     236             :                 /* Don't store non-real name types. */
     237         420 :                 goto out;
     238             :         }
     239             : 
     240         424 :         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         424 :         key = namecache_key(frame, name, name_type);
     260         424 :         if (!key) {
     261           0 :                 goto out;
     262             :         }
     263             : 
     264         424 :         expiry = time(NULL) + lp_name_cache_timeout();
     265             : 
     266             :         /*
     267             :          * Generate string representation of ip addresses list
     268             :          */
     269         424 :         value_string = ipstr_list_make_sa(frame, sa_list, num_names);
     270         424 :         if (value_string == NULL) {
     271           0 :                 goto out;
     272             :         }
     273             : 
     274             :         /* set the entry */
     275         424 :         ret = gencache_set(key, value_string, expiry);
     276             : 
     277         844 :   out:
     278             : 
     279         844 :         TALLOC_FREE(key);
     280         844 :         TALLOC_FREE(value_string);
     281         844 :         TALLOC_FREE(frame);
     282         844 :         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        9054 : 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        9054 :         if (name_type > 255) {
     308         420 :                 return false; /* Don't fetch non-real name types. */
     309             :         }
     310             : 
     311        8634 :         *num_names = 0;
     312             : 
     313             :         /*
     314             :          * Use gencache interface - lookup the key
     315             :          */
     316        8634 :         key = namecache_key(talloc_tos(), name, name_type);
     317        8634 :         if (!key) {
     318           0 :                 return false;
     319             :         }
     320             : 
     321        8634 :         if (!gencache_get(key, talloc_tos(), &value, &timeout)) {
     322         434 :                 DBG_INFO("no entry for %s#%02X found.\n", name, name_type);
     323         434 :                 TALLOC_FREE(key);
     324         434 :                 return false;
     325             :         }
     326             : 
     327        8200 :         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        8200 :         *num_names = ipstr_list_parse(ctx, value, sa_list);
     333             : 
     334        8200 :         TALLOC_FREE(key);
     335        8200 :         TALLOC_FREE(value);
     336             : 
     337        8200 :         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          76 : 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          76 :         print_sockaddr(addr, sizeof(addr), keyip);
     407          76 :         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          28 : 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          28 :         key = namecache_status_record_key(talloc_tos(),
     426             :                                           keyname,
     427             :                                           keyname_type,
     428             :                                           name_type,
     429             :                                           keyip);
     430          28 :         if (!key)
     431           0 :                 return false;
     432             : 
     433          28 :         expiry = time(NULL) + lp_name_cache_timeout();
     434          28 :         ret = gencache_set(key, srvname, expiry);
     435             : 
     436          28 :         if (ret) {
     437          28 :                 DBG_INFO("entry %s -> %s\n", key, srvname);
     438             :         } else {
     439           0 :                 DBG_INFO("entry %s store failed.\n", key);
     440             :         }
     441             : 
     442          28 :         TALLOC_FREE(key);
     443          28 :         return ret;
     444             : }
     445             : 
     446             : /* Fetch a name status record. */
     447             : 
     448          48 : 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          48 :         char *key = NULL;
     455          48 :         char *value = NULL;
     456             :         time_t timeout;
     457             : 
     458          48 :         key = namecache_status_record_key(talloc_tos(),
     459             :                                           keyname,
     460             :                                           keyname_type,
     461             :                                           name_type,
     462             :                                           keyip);
     463          48 :         if (!key)
     464           0 :                 return false;
     465             : 
     466          48 :         if (!gencache_get(key, talloc_tos(), &value, &timeout)) {
     467          44 :                 DBG_INFO("no entry for %s found.\n", key);
     468          44 :                 TALLOC_FREE(key);
     469          44 :                 return false;
     470             :         } else {
     471           4 :                 DBG_INFO("key %s -> %s\n", key, value);
     472             :         }
     473             : 
     474           4 :         strlcpy(srvname_out, value, 16);
     475           4 :         TALLOC_FREE(key);
     476           4 :         TALLOC_FREE(value);
     477           4 :         return true;
     478             : }

Generated by: LCOV version 1.13