]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/hstcache.c
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[thirdparty/glibc.git] / nscd / hstcache.c
CommitLineData
67479a70 1/* Cache handling for host lookup.
a334319f 2 Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
67479a70
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
a334319f
UD
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.
67479a70 10
a334319f 11 The GNU C Library is distributed in the hope that it will be useful,
67479a70 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
a334319f
UD
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
67479a70 15
a334319f
UD
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. */
67479a70 20
9caf4f1c 21#include <alloca.h>
67479a70
UD
22#include <assert.h>
23#include <errno.h>
24#include <error.h>
a95a08b4 25#include <libintl.h>
67479a70 26#include <netdb.h>
c7a9b6e2 27#include <stdbool.h>
67479a70
UD
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>
9e56c380 35#include <arpa/nameser.h>
a95a08b4 36#include <sys/mman.h>
c7a9b6e2 37#include <stackinfo.h>
67479a70
UD
38
39#include "nscd.h"
40#include "dbg_log.h"
41
67479a70
UD
42
43/* This is the standard reply in case the service is disabled. */
44static const hst_response_header disabled =
45{
c2e13112
RM
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
67479a70
UD
54};
55
56/* This is the struct describing how to write this record. */
57const struct iovec hst_iov_disabled =
58{
c2e13112
RM
59 .iov_base = (void *) &disabled,
60 .iov_len = sizeof (disabled)
67479a70
UD
61};
62
63
64/* This is the standard reply in case we haven't found the dataset. */
65static const hst_response_header notfound =
66{
c2e13112
RM
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
67479a70
UD
75};
76
67479a70 77
67479a70 78static void
a95a08b4 79cache_addhst (struct database_dyn *db, int fd, request_header *req,
c207f23b 80 const void *key, struct hostent *hst, uid_t owner,
a95a08b4 81 struct hashentry *he, struct datahead *dh, int errval)
67479a70
UD
82{
83 ssize_t total;
84 ssize_t written;
85 time_t t = time (NULL);
86
a95a08b4
UD
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
67479a70
UD
98 if (hst == NULL)
99 {
a95a08b4
UD
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);
67479a70 116
a95a08b4 117 if (fd != -1)
a334319f 118 written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
67479a70 119
a95a08b4
UD
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;
67479a70 129
a95a08b4
UD
130 /* Compute the timeout time. */
131 dataset->head.timeout = t + db->negtimeout;
67479a70 132
a95a08b4
UD
133 /* This is the reply. */
134 memcpy (&dataset->resp, &notfound, total);
67479a70 135
a95a08b4
UD
136 /* Copy the key data. */
137 memcpy (dataset->strdata, key, req->key_len);
67479a70 138
8c89236f
UD
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
a95a08b4
UD
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;
99bb9f42 165 }
67479a70
UD
166 }
167 else
168 {
169 /* Determine the I/O structure. */
67479a70
UD
170 size_t h_name_len = strlen (hst->h_name) + 1;
171 size_t h_aliases_cnt;
3107c0c5 172 uint32_t *h_aliases_len;
67479a70
UD
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. */
3107c0c5 186 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
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
a95a08b4
UD
199 if (h_addr_list_cnt == 0)
200 /* Invalid entry. */
201 return;
202
203 total += (sizeof (struct dataset)
67479a70 204 + h_name_len
3107c0c5 205 + h_aliases_cnt * sizeof (uint32_t)
488fb3c7 206 + h_addr_list_cnt * hst->h_length);
a95a08b4 207 written = total;
67479a70 208
a95a08b4
UD
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;
67479a70 215
a95a08b4
UD
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. */
c207f23b 221 if (he == NULL && hst->h_addr_list[1] == NULL)
a95a08b4
UD
222 {
223 dataset = (struct dataset *) mempool_alloc (db,
224 total + req->key_len);
225 if (dataset == NULL)
226 ++db->head->addfailed;
227 }
67479a70 228
a95a08b4
UD
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;
67479a70
UD
259
260 cp = mempcpy (cp, hst->h_name, h_name_len);
3107c0c5 261 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
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
67479a70
UD
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
a95a08b4
UD
273 assert (cp
274 == dataset->strdata + total - offsetof (struct dataset,
275 strdata));
67479a70
UD
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. */
c207f23b 282 key_copy = memcpy (cp, key, req->key_len);
67479a70 283
a95a08b4
UD
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);
67479a70 289
a95a08b4
UD
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 {
8c89236f 295 /* The data has not changed. We will just bump the
a95a08b4
UD
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
490998a5 324 {
a95a08b4
UD
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
a334319f 330 written = TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
490998a5
UD
331 }
332
a95a08b4
UD
333 /* Add the record to the database. But only if it has not been
334 stored on the stack.
67479a70 335
a95a08b4
UD
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)
67479a70 342 {
a95a08b4
UD
343 /* If necessary, we also propagate the data to disk. */
344 if (db->persistent)
3418007e
UD
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 }
a95a08b4
UD
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. */
c207f23b 364 assert (hst->h_addr_list[1] == NULL);
a95a08b4 365
a95a08b4
UD
366 /* Avoid adding names if more than one address is available. See
367 above for more info. */
c207f23b
UD
368 assert (req->type == GETHOSTBYNAME
369 || req->type == GETHOSTBYNAMEv6
370 || req->type == GETHOSTBYADDR
371 || req->type == GETHOSTBYADDRv6);
a95a08b4 372
c207f23b
UD
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;
a95a08b4 378
a95a08b4 379 pthread_rwlock_unlock (&db->lock);
67479a70 380 }
67479a70
UD
381 }
382
23700036 383 if (__builtin_expect (written != total, 0) && debug_level > 0)
67479a70
UD
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
a95a08b4
UD
392static int
393lookup (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);
8c89236f 399 if (type == GETHOSTBYNAMEv6)
a95a08b4
UD
400 return __gethostbyname2_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
401 &h_errno);
8c89236f 402 if (type == GETHOSTBYADDR)
a95a08b4
UD
403 return __gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
404 buflen, hst, &h_errno);
8c89236f
UD
405 return __gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
406 buflen, hst, &h_errno);
a95a08b4
UD
407}
408
409
410static void
411addhstbyX (struct database_dyn *db, int fd, request_header *req,
412 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
67479a70
UD
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. */
c7a9b6e2
UD
418 int buflen = 1024;
419 char *buffer = (char *) alloca (buflen);
67479a70
UD
420 struct hostent resultbuf;
421 struct hostent *hst;
c7a9b6e2 422 bool use_malloc = false;
a95a08b4 423 int errval = 0;
67479a70 424
c7a9b6e2 425 if (__builtin_expect (debug_level > 0, 0))
a95a08b4 426 {
c207f23b
UD
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
a95a08b4 435 if (he == NULL)
c207f23b 436 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
a95a08b4 437 else
c207f23b 438 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
a95a08b4 439 }
67479a70 440
3c12b91a
UD
441#if 0
442 uid_t oldeuid = 0;
a95a08b4 443 if (db->secure)
a1c542bf
UD
444 {
445 oldeuid = geteuid ();
2edb61e3 446 pthread_seteuid_np (uid);
a1c542bf 447 }
3c12b91a 448#endif
a1c542bf 449
a95a08b4 450 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst) != 0
67479a70 451 && h_errno == NETDB_INTERNAL
a95a08b4 452 && (errval = errno) == ERANGE)
67479a70 453 {
c7a9b6e2 454 char *old_buffer = buffer;
67479a70 455 errno = 0;
a334319f 456#define INCR 1024
c7a9b6e2
UD
457
458 if (__builtin_expect (buflen > 32768, 0))
459 {
a334319f 460 buflen += INCR;
c7a9b6e2
UD
461 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
462 if (buffer == NULL)
463 {
464 /* We ran out of memory. We cannot do anything but
465 sending a negative response. In reality this should
466 never happen. */
467 hst = NULL;
468 buffer = old_buffer;
a95a08b4
UD
469
470 /* We set the error to indicate this is (possibly) a
471 temporary error and that it does not mean the entry
472 is not available at all. */
473 errval = EAGAIN;
c7a9b6e2
UD
474 break;
475 }
476 use_malloc = true;
477 }
478 else
9caf4f1c
UD
479 /* Allocate a new buffer on the stack. If possible combine it
480 with the previously allocated buffer. */
a334319f 481 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
67479a70
UD
482 }
483
3c12b91a 484#if 0
a95a08b4 485 if (db->secure)
2edb61e3 486 pthread_seteuid_np (oldeuid);
3c12b91a 487#endif
a1c542bf 488
c207f23b 489 cache_addhst (db, fd, req, key, hst, uid, he, dh,
a95a08b4 490 h_errno == TRY_AGAIN ? errval : 0);
c7a9b6e2
UD
491
492 if (use_malloc)
493 free (buffer);
67479a70
UD
494}
495
496
497void
a95a08b4 498addhstbyname (struct database_dyn *db, int fd, request_header *req,
a1c542bf 499 void *key, uid_t uid)
67479a70 500{
a95a08b4
UD
501 addhstbyX (db, fd, req, key, uid, NULL, NULL);
502}
67479a70 503
67479a70 504
a95a08b4
UD
505void
506readdhstbyname (struct database_dyn *db, struct hashentry *he,
507 struct datahead *dh)
508{
509 request_header req =
a1c542bf 510 {
a95a08b4
UD
511 .type = GETHOSTBYNAME,
512 .key_len = he->len
513 };
a1c542bf 514
a95a08b4
UD
515 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
516}
c7a9b6e2 517
67479a70 518
a95a08b4
UD
519void
520addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
521 void *key, uid_t uid)
522{
523 addhstbyX (db, fd, req, key, uid, NULL, NULL);
524}
a1c542bf 525
c7a9b6e2 526
a95a08b4
UD
527void
528readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
529 struct datahead *dh)
530{
531 request_header req =
532 {
533 .type = GETHOSTBYADDR,
534 .key_len = he->len
535 };
536
537 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
538}
539
540
541void
a95a08b4 542addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 543 void *key, uid_t uid)
67479a70 544{
a95a08b4
UD
545 addhstbyX (db, fd, req, key, uid, NULL, NULL);
546}
67479a70 547
a1c542bf 548
a95a08b4
UD
549void
550readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
551 struct datahead *dh)
552{
553 request_header req =
67479a70 554 {
a95a08b4
UD
555 .type = GETHOSTBYNAMEv6,
556 .key_len = he->len
557 };
c7a9b6e2 558
a95a08b4 559 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
560}
561
562
563void
a95a08b4 564addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 565 void *key, uid_t uid)
67479a70 566{
a95a08b4
UD
567 addhstbyX (db, fd, req, key, uid, NULL, NULL);
568}
67479a70 569
67479a70 570
a95a08b4
UD
571void
572readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
573 struct datahead *dh)
574{
575 request_header req =
67479a70 576 {
a95a08b4
UD
577 .type = GETHOSTBYADDRv6,
578 .key_len = he->len
579 };
c7a9b6e2 580
a95a08b4 581 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70 582}