LCOV - code coverage report
Current view: top level - source3/libsmb - namecache.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 117 171 68.4 %
Date: 2024-04-21 15:09:00 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 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             : }

Generated by: LCOV version 1.14