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