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