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