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