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