(root)/
glibc-2.38/
nscd/
hstcache.c
       1  /* Cache handling for host lookup.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     This program is free software; you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published
       7     by the Free Software Foundation; version 2 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <alloca.h>
      19  #include <assert.h>
      20  #include <errno.h>
      21  #include <error.h>
      22  #include <libintl.h>
      23  #include <netdb.h>
      24  #include <stdbool.h>
      25  #include <stddef.h>
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  #include <time.h>
      30  #include <unistd.h>
      31  #include <stdint.h>
      32  #include <arpa/inet.h>
      33  #include <arpa/nameser.h>
      34  #include <sys/mman.h>
      35  #include <stackinfo.h>
      36  #include <scratch_buffer.h>
      37  
      38  #include "nscd.h"
      39  #include "dbg_log.h"
      40  
      41  
      42  /* This is the standard reply in case the service is disabled.  */
      43  static const hst_response_header disabled =
      44  {
      45    .version = NSCD_VERSION,
      46    .found = -1,
      47    .h_name_len = 0,
      48    .h_aliases_cnt = 0,
      49    .h_addrtype = -1,
      50    .h_length = -1,
      51    .h_addr_list_cnt = 0,
      52    .error = NETDB_INTERNAL
      53  };
      54  
      55  /* This is the struct describing how to write this record.  */
      56  const struct iovec hst_iov_disabled =
      57  {
      58    .iov_base = (void *) &disabled,
      59    .iov_len = sizeof (disabled)
      60  };
      61  
      62  
      63  /* This is the standard reply in case we haven't found the dataset.  */
      64  static const hst_response_header notfound =
      65  {
      66    .version = NSCD_VERSION,
      67    .found = 0,
      68    .h_name_len = 0,
      69    .h_aliases_cnt = 0,
      70    .h_addrtype = -1,
      71    .h_length = -1,
      72    .h_addr_list_cnt = 0,
      73    .error = HOST_NOT_FOUND
      74  };
      75  
      76  
      77  /* This is the standard reply in case there are temporary problems.  */
      78  static const hst_response_header tryagain =
      79  {
      80    .version = NSCD_VERSION,
      81    .found = 0,
      82    .h_name_len = 0,
      83    .h_aliases_cnt = 0,
      84    .h_addrtype = -1,
      85    .h_length = -1,
      86    .h_addr_list_cnt = 0,
      87    .error = TRY_AGAIN
      88  };
      89  
      90  
      91  static time_t
      92  cache_addhst (struct database_dyn *db, int fd, request_header *req,
      93  	      const void *key, struct hostent *hst, uid_t owner,
      94  	      struct hashentry *const he, struct datahead *dh, int errval,
      95  	      int32_t ttl)
      96  {
      97    bool all_written = true;
      98    time_t t = time (NULL);
      99  
     100    /* We allocate all data in one memory block: the iov vector,
     101       the response header and the dataset itself.  */
     102    struct dataset
     103    {
     104      struct datahead head;
     105      hst_response_header resp;
     106      char strdata[0];
     107    } *dataset;
     108  
     109    assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
     110  
     111    time_t timeout = MAX_TIMEOUT_VALUE;
     112    if (hst == NULL)
     113      {
     114        if (he != NULL && errval == EAGAIN)
     115  	{
     116  	  /* If we have an old record available but cannot find one
     117  	     now because the service is not available we keep the old
     118  	     record and make sure it does not get removed.  */
     119  	  if (reload_count != UINT_MAX)
     120  	    /* Do not reset the value if we never not reload the record.  */
     121  	    dh->nreloads = reload_count - 1;
     122  
     123  	  /* Reload with the same time-to-live value.  */
     124  	  timeout = dh->timeout = t + dh->ttl;
     125  	}
     126        else
     127  	{
     128  	  /* We have no data.  This means we send the standard reply for this
     129  	     case.  Possibly this is only temporary.  */
     130  	  ssize_t total = sizeof (notfound);
     131  	  assert (sizeof (notfound) == sizeof (tryagain));
     132  
     133  	  const hst_response_header *resp = (errval == EAGAIN
     134  					     ? &tryagain : &notfound);
     135  
     136  	  if (fd != -1
     137  	      && TEMP_FAILURE_RETRY (send (fd, resp, total,
     138  					   MSG_NOSIGNAL)) != total)
     139  	    all_written = false;
     140  
     141  	  /* If we have a transient error or cannot permanently store
     142  	     the result, so be it.  */
     143  	  if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
     144  	    {
     145  	      /* Mark the old entry as obsolete.  */
     146  	      if (dh != NULL)
     147  		dh->usable = false;
     148  	    }
     149  	  else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
     150  						  + req->key_len), 1)) != NULL)
     151  	    {
     152  	      timeout = datahead_init_neg (&dataset->head,
     153  					   (sizeof (struct dataset)
     154  					    + req->key_len), total,
     155  					   (ttl == INT32_MAX
     156  					    ? db->negtimeout : ttl));
     157  
     158  	      /* This is the reply.  */
     159  	      memcpy (&dataset->resp, resp, total);
     160  
     161  	      /* Copy the key data.  */
     162  	      memcpy (dataset->strdata, key, req->key_len);
     163  
     164  	      /* If necessary, we also propagate the data to disk.  */
     165  	      if (db->persistent)
     166  		{
     167  		  // XXX async OK?
     168  		  uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
     169  		  msync ((void *) pval,
     170  			 ((uintptr_t) dataset & pagesize_m1)
     171  			 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
     172  		}
     173  
     174  	      (void) cache_add (req->type, &dataset->strdata, req->key_len,
     175  				&dataset->head, true, db, owner, he == NULL);
     176  
     177  	      pthread_rwlock_unlock (&db->lock);
     178  
     179  	      /* Mark the old entry as obsolete.  */
     180  	      if (dh != NULL)
     181  		dh->usable = false;
     182  	    }
     183  	}
     184      }
     185    else
     186      {
     187        /* Determine the I/O structure.  */
     188        size_t h_name_len = strlen (hst->h_name) + 1;
     189        size_t h_aliases_cnt;
     190        uint32_t *h_aliases_len;
     191        size_t h_addr_list_cnt;
     192        char *addresses;
     193        char *aliases;
     194        char *key_copy = NULL;
     195        char *cp;
     196        size_t cnt;
     197        ssize_t total;
     198  
     199        /* Determine the number of aliases.  */
     200        h_aliases_cnt = 0;
     201        for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
     202  	++h_aliases_cnt;
     203        /* Determine the length of all aliases.  */
     204        h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
     205        total = 0;
     206        for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
     207  	{
     208  	  h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
     209  	  total += h_aliases_len[cnt];
     210  	}
     211  
     212        /* Determine the number of addresses.  */
     213        h_addr_list_cnt = 0;
     214        while (hst->h_addr_list[h_addr_list_cnt] != NULL)
     215  	++h_addr_list_cnt;
     216  
     217        if (h_addr_list_cnt == 0)
     218  	/* Invalid entry.  */
     219  	return MAX_TIMEOUT_VALUE;
     220  
     221        total += (sizeof (struct dataset)
     222  		+ h_name_len
     223  		+ h_aliases_cnt * sizeof (uint32_t)
     224  		+ h_addr_list_cnt * hst->h_length);
     225  
     226        /* If we refill the cache, first assume the reconrd did not
     227  	 change.  Allocate memory on the cache since it is likely
     228  	 discarded anyway.  If it turns out to be necessary to have a
     229  	 new record we can still allocate real memory.  */
     230        bool alloca_used = false;
     231        dataset = NULL;
     232  
     233        /* If the record contains more than one IP address (used for
     234  	 load balancing etc) don't cache the entry.  This is something
     235  	 the current cache handling cannot handle and it is more than
     236  	 questionable whether it is worthwhile complicating the cache
     237  	 handling just for handling such a special case. */
     238        if (he == NULL && h_addr_list_cnt == 1)
     239  	dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
     240  						    1);
     241  
     242        if (dataset == NULL)
     243  	{
     244  	  /* We cannot permanently add the result in the moment.  But
     245  	     we can provide the result as is.  Store the data in some
     246  	     temporary memory.  */
     247  	  dataset = (struct dataset *) alloca (total + req->key_len);
     248  
     249  	  /* We cannot add this record to the permanent database.  */
     250  	  alloca_used = true;
     251  	}
     252  
     253        timeout = datahead_init_pos (&dataset->head, total + req->key_len,
     254  				   total - offsetof (struct dataset, resp),
     255  				   he == NULL ? 0 : dh->nreloads + 1,
     256  				   ttl == INT32_MAX ? db->postimeout : ttl);
     257  
     258        dataset->resp.version = NSCD_VERSION;
     259        dataset->resp.found = 1;
     260        dataset->resp.h_name_len = h_name_len;
     261        dataset->resp.h_aliases_cnt = h_aliases_cnt;
     262        dataset->resp.h_addrtype = hst->h_addrtype;
     263        dataset->resp.h_length = hst->h_length;
     264        dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
     265        dataset->resp.error = NETDB_SUCCESS;
     266  
     267        /* Make sure there is no gap.  */
     268        assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
     269  
     270        cp = dataset->strdata;
     271  
     272        cp = mempcpy (cp, hst->h_name, h_name_len);
     273        cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
     274  
     275        /* The normal addresses first.  */
     276        addresses = cp;
     277        for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
     278  	cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
     279  
     280        /* Then the aliases.  */
     281        aliases = cp;
     282        for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
     283  	cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
     284  
     285        assert (cp
     286  	      == dataset->strdata + total - offsetof (struct dataset,
     287  						      strdata));
     288  
     289        /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
     290  	 that the answer we get from the NSS does not contain the key
     291  	 itself.  This is the case if the resolver is used and the name
     292  	 is extended by the domainnames from /etc/resolv.conf.  Therefore
     293  	 we explicitly add the name here.  */
     294        key_copy = memcpy (cp, key, req->key_len);
     295  
     296        assert ((char *) &dataset->resp + dataset->head.recsize == cp);
     297  
     298        /* Now we can determine whether on refill we have to create a new
     299  	 record or not.  */
     300        if (he != NULL)
     301  	{
     302  	  assert (fd == -1);
     303  
     304  	  if (total + req->key_len == dh->allocsize
     305  	      && total - offsetof (struct dataset, resp) == dh->recsize
     306  	      && memcmp (&dataset->resp, dh->data,
     307  			 dh->allocsize - offsetof (struct dataset, resp)) == 0)
     308  	    {
     309  	      /* The data has not changed.  We will just bump the
     310  		 timeout value.  Note that the new record has been
     311  		 allocated on the stack and need not be freed.  */
     312  	      assert (h_addr_list_cnt == 1);
     313  	      dh->ttl = dataset->head.ttl;
     314  	      dh->timeout = dataset->head.timeout;
     315  	      ++dh->nreloads;
     316  	    }
     317  	  else
     318  	    {
     319  	      if (h_addr_list_cnt == 1)
     320  		{
     321  		  /* We have to create a new record.  Just allocate
     322  		     appropriate memory and copy it.  */
     323  		  struct dataset *newp
     324  		    = (struct dataset *) mempool_alloc (db,
     325  							total + req->key_len,
     326  							1);
     327  		  if (newp != NULL)
     328  		    {
     329  		      /* Adjust pointers into the memory block.  */
     330  		      addresses = (char *) newp + (addresses
     331  						   - (char *) dataset);
     332  		      aliases = (char *) newp + (aliases - (char *) dataset);
     333  		      assert (key_copy != NULL);
     334  		      key_copy = (char *) newp + (key_copy - (char *) dataset);
     335  
     336  		      dataset = memcpy (newp, dataset, total + req->key_len);
     337  		      alloca_used = false;
     338  		    }
     339  		}
     340  
     341  	      /* Mark the old record as obsolete.  */
     342  	      dh->usable = false;
     343  	    }
     344  	}
     345        else
     346  	{
     347  	  /* We write the dataset before inserting it to the database
     348  	     since while inserting this thread might block and so would
     349  	     unnecessarily keep the receiver waiting.  */
     350  	  assert (fd != -1);
     351  
     352  	  if (writeall (fd, &dataset->resp, dataset->head.recsize)
     353  	      != dataset->head.recsize)
     354  	    all_written = false;
     355  	}
     356  
     357        /* Add the record to the database.  But only if it has not been
     358  	 stored on the stack.
     359  
     360  	 If the record contains more than one IP address (used for
     361  	 load balancing etc) don't cache the entry.  This is something
     362  	 the current cache handling cannot handle and it is more than
     363  	 questionable whether it is worthwhile complicating the cache
     364  	 handling just for handling such a special case. */
     365        if (! alloca_used)
     366  	{
     367  	  /* If necessary, we also propagate the data to disk.  */
     368  	  if (db->persistent)
     369  	    {
     370  	      // XXX async OK?
     371  	      uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
     372  	      msync ((void *) pval,
     373  		     ((uintptr_t) dataset & pagesize_m1)
     374  		     + total + req->key_len, MS_ASYNC);
     375  	    }
     376  
     377  	  /* NB: the following code is really complicated.  It has
     378  	     seemlingly duplicated code paths which do the same.  The
     379  	     problem is that we always must add the hash table entry
     380  	     with the FIRST flag set first.  Otherwise we get dangling
     381  	     pointers in case memory allocation fails.  */
     382  	  assert (hst->h_addr_list[1] == NULL);
     383  
     384  	  /* Avoid adding names if more than one address is available.  See
     385  	     above for more info.  */
     386  	  assert (req->type == GETHOSTBYNAME
     387  		  || req->type == GETHOSTBYNAMEv6
     388  		  || req->type == GETHOSTBYADDR
     389  		  || req->type == GETHOSTBYADDRv6);
     390  
     391  	  (void) cache_add (req->type, key_copy, req->key_len,
     392  			    &dataset->head, true, db, owner, he == NULL);
     393  
     394  	  pthread_rwlock_unlock (&db->lock);
     395  	}
     396      }
     397  
     398    if (__builtin_expect (!all_written, 0) && debug_level > 0)
     399      {
     400        char buf[256];
     401        dbg_log (_("short write in %s: %s"),  __FUNCTION__,
     402  	       strerror_r (errno, buf, sizeof (buf)));
     403      }
     404  
     405    return timeout;
     406  }
     407  
     408  
     409  static int
     410  lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
     411  	size_t buflen, struct hostent **hst, int32_t *ttlp)
     412  {
     413    if (type == GETHOSTBYNAME)
     414      return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
     415  			       &h_errno, ttlp, NULL);
     416    if (type == GETHOSTBYNAMEv6)
     417      return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
     418  			       &h_errno, ttlp, NULL);
     419    if (type == GETHOSTBYADDR)
     420      return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
     421  			       buflen, hst, &h_errno, ttlp);
     422    return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
     423  			     buflen, hst, &h_errno, ttlp);
     424  }
     425  
     426  
     427  static time_t
     428  addhstbyX (struct database_dyn *db, int fd, request_header *req,
     429  	   void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
     430  {
     431    /* Search for the entry matching the key.  Please note that we don't
     432       look again in the table whether the dataset is now available.  We
     433       simply insert it.  It does not matter if it is in there twice.  The
     434       pruning function only will look at the timestamp.  */
     435    struct hostent resultbuf;
     436    struct hostent *hst;
     437    int errval = 0;
     438    int32_t ttl = INT32_MAX;
     439  
     440    if (__glibc_unlikely (debug_level > 0))
     441      {
     442        const char *str;
     443        char buf[INET6_ADDRSTRLEN + 1];
     444        if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
     445  	str = key;
     446        else
     447  	str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
     448  			 key, buf, sizeof (buf));
     449  
     450        if (he == NULL)
     451  	dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
     452        else
     453  	dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
     454      }
     455  
     456    struct scratch_buffer tmpbuf;
     457    scratch_buffer_init (&tmpbuf);
     458  
     459    while (lookup (req->type, key, &resultbuf,
     460  		 tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
     461  	 && h_errno == NETDB_INTERNAL
     462  	 && (errval = errno) == ERANGE)
     463      if (!scratch_buffer_grow (&tmpbuf))
     464        {
     465  	/* We ran out of memory.  We cannot do anything but sending a
     466  	   negative response.  In reality this should never
     467  	   happen.  */
     468  	hst = NULL;
     469  	/* We set the error to indicate this is (possibly) a temporary
     470  	   error and that it does not mean the entry is not
     471  	   available at all.  */
     472  	h_errno = TRY_AGAIN;
     473  	errval = EAGAIN;
     474  	break;
     475        }
     476  
     477    time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
     478  				 h_errno == TRY_AGAIN ? errval : 0, ttl);
     479    scratch_buffer_free (&tmpbuf);
     480    return timeout;
     481  }
     482  
     483  
     484  void
     485  addhstbyname (struct database_dyn *db, int fd, request_header *req,
     486  	      void *key, uid_t uid)
     487  {
     488    addhstbyX (db, fd, req, key, uid, NULL, NULL);
     489  }
     490  
     491  
     492  time_t
     493  readdhstbyname (struct database_dyn *db, struct hashentry *he,
     494  		struct datahead *dh)
     495  {
     496    request_header req =
     497      {
     498        .type = GETHOSTBYNAME,
     499        .key_len = he->len
     500      };
     501  
     502    return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
     503  }
     504  
     505  
     506  void
     507  addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
     508  	      void *key, uid_t uid)
     509  {
     510    addhstbyX (db, fd, req, key, uid, NULL, NULL);
     511  }
     512  
     513  
     514  time_t
     515  readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
     516  		struct datahead *dh)
     517  {
     518    request_header req =
     519      {
     520        .type = GETHOSTBYADDR,
     521        .key_len = he->len
     522      };
     523  
     524    return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
     525  }
     526  
     527  
     528  void
     529  addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
     530  		void *key, uid_t uid)
     531  {
     532    addhstbyX (db, fd, req, key, uid, NULL, NULL);
     533  }
     534  
     535  
     536  time_t
     537  readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
     538  		  struct datahead *dh)
     539  {
     540    request_header req =
     541      {
     542        .type = GETHOSTBYNAMEv6,
     543        .key_len = he->len
     544      };
     545  
     546    return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
     547  }
     548  
     549  
     550  void
     551  addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
     552  		void *key, uid_t uid)
     553  {
     554    addhstbyX (db, fd, req, key, uid, NULL, NULL);
     555  }
     556  
     557  
     558  time_t
     559  readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
     560  		  struct datahead *dh)
     561  {
     562    request_header req =
     563      {
     564        .type = GETHOSTBYADDRv6,
     565        .key_len = he->len
     566      };
     567  
     568    return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
     569  }