Update.
[platform/upstream/glibc.git] / nscd / hstcache.c
1 /* Cache handling for host lookup.
2    Copyright (C) 1998, 1999, 2000, 2001, 2002 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 <assert.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <netdb.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <libintl.h>
33 #include <arpa/inet.h>
34 #include <arpa/nameser.h>
35 #include <stackinfo.h>
36
37 #include "nscd.h"
38 #include "dbg_log.h"
39
40
41 /* This is the standard reply in case the service is disabled.  */
42 static const hst_response_header disabled =
43 {
44   version: NSCD_VERSION,
45   found: -1,
46   h_name_len: 0,
47   h_aliases_cnt: 0,
48   h_addrtype: -1,
49   h_length: -1,
50   h_addr_list_cnt: 0,
51   error: NETDB_INTERNAL
52 };
53
54 /* This is the struct describing how to write this record.  */
55 const struct iovec hst_iov_disabled =
56 {
57   iov_base: (void *) &disabled,
58   iov_len: sizeof (disabled)
59 };
60
61
62 /* This is the standard reply in case we haven't found the dataset.  */
63 static const hst_response_header notfound =
64 {
65   version: NSCD_VERSION,
66   found: 0,
67   h_name_len: 0,
68   h_aliases_cnt: 0,
69   h_addrtype: -1,
70   h_length: -1,
71   h_addr_list_cnt: 0,
72   error: HOST_NOT_FOUND
73 };
74
75 /* This is the struct describing how to write this record.  */
76 static const struct iovec iov_notfound =
77 {
78   iov_base: (void *) &notfound,
79   iov_len: sizeof (notfound)
80 };
81
82
83 struct hostdata
84 {
85   hst_response_header resp;
86   char strdata[0];
87 };
88
89
90 static void
91 cache_addhst (struct database *db, int fd, request_header *req, void *key,
92               struct hostent *hst, uid_t owner)
93 {
94   ssize_t total;
95   ssize_t written;
96   time_t t = time (NULL);
97
98   if (hst == NULL)
99     {
100       /* We have no data.  This means we send the standard reply for this
101          case.  */
102       void *copy;
103
104       total = sizeof (notfound);
105
106       written = writev (fd, &iov_notfound, 1);
107
108       copy = malloc (req->key_len);
109       if (copy == NULL)
110         error (EXIT_FAILURE, errno, _("while allocating key copy"));
111       memcpy (copy, key, req->key_len);
112
113       /* Compute the timeout time.  */
114       t += db->negtimeout;
115
116       /* Now get the lock to safely insert the records.  */
117       pthread_rwlock_rdlock (&db->lock);
118
119       cache_add (req->type, copy, req->key_len, &notfound,
120                  sizeof (notfound), (void *) -1, 0, t, db, owner);
121
122       pthread_rwlock_unlock (&db->lock);
123     }
124   else
125     {
126       /* Determine the I/O structure.  */
127       struct hostdata *data;
128       size_t h_name_len = strlen (hst->h_name) + 1;
129       size_t h_aliases_cnt;
130       uint32_t *h_aliases_len;
131       size_t h_addr_list_cnt;
132       int addr_list_type;
133       char *addresses;
134       char *aliases;
135       char *key_copy = NULL;
136       char *cp;
137       size_t cnt;
138
139       /* Determine the number of aliases.  */
140       h_aliases_cnt = 0;
141       for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
142         ++h_aliases_cnt;
143       /* Determine the length of all aliases.  */
144       h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
145       total = 0;
146       for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
147         {
148           h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
149           total += h_aliases_len[cnt];
150         }
151
152       /* Determine the number of addresses.  */
153       h_addr_list_cnt = 0;
154       for (cnt = 0; hst->h_addr_list[cnt]; ++cnt)
155         ++h_addr_list_cnt;
156
157       /* We allocate all data in one memory block: the iov vector,
158          the response header and the dataset itself.  */
159       total += (sizeof (struct hostdata)
160                 + h_name_len
161                 + h_aliases_cnt * sizeof (uint32_t)
162                 + h_addr_list_cnt * hst->h_length);
163
164       data = (struct hostdata *) malloc (total + req->key_len);
165       if (data == NULL)
166         /* There is no reason to go on.  */
167         error (EXIT_FAILURE, errno, _("while allocating cache entry"));
168
169       data->resp.found = 1;
170       data->resp.h_name_len = h_name_len;
171       data->resp.h_aliases_cnt = h_aliases_cnt;
172       data->resp.h_addrtype = hst->h_addrtype;
173       data->resp.h_length = hst->h_length;
174       data->resp.h_addr_list_cnt = h_addr_list_cnt;
175       data->resp.error = NETDB_SUCCESS;
176
177       cp = data->strdata;
178
179       cp = mempcpy (cp, hst->h_name, h_name_len);
180       cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
181
182       /* The normal addresses first.  */
183       addresses = cp;
184       for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
185         cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
186
187       /* Then the aliases.  */
188       aliases = cp;
189       for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
190         cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
191
192       assert (cp == data->strdata + total - sizeof (hst_response_header));
193
194       /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
195          that the answer we get from the NSS does not contain the key
196          itself.  This is the case if the resolver is used and the name
197          is extended by the domainnames from /etc/resolv.conf.  Therefore
198          we explicitly add the name here.  */
199       if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
200         key_copy = memcpy (cp, key, req->key_len);
201
202       /* We write the dataset before inserting it to the database
203          since while inserting this thread might block and so would
204          unnecessarily let the receiver wait.  */
205       written = TEMP_FAILURE_RETRY (write (fd, data, total));
206
207       addr_list_type = (hst->h_length == NS_INADDRSZ
208                         ? GETHOSTBYADDR : GETHOSTBYADDRv6);
209
210       /* Compute the timeout time.  */
211       t += db->postimeout;
212
213       /* Now get the lock to safely insert the records.  */
214       pthread_rwlock_rdlock (&db->lock);
215
216       /* First add all the aliases.  If the record contains more than
217          one IP address (used for load balancing etc) don't cache the
218          entry.  This is something the current cache handling cannot
219          handle and it is more than questionable whether it is
220          worthwhile complicating the cache handling just for handling
221          such a special case.  */
222       if (hst->h_addr_list[1] == NULL)
223         for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
224           {
225             if (addr_list_type == GETHOSTBYADDR)
226               cache_add (GETHOSTBYNAME, aliases, h_aliases_len[cnt], data,
227                          total, data, 0, t, db, owner);
228
229             cache_add (GETHOSTBYNAMEv6, aliases, h_aliases_len[cnt], data,
230                        total, data, 0, t, db, owner);
231
232             aliases += h_aliases_len[cnt];
233           }
234
235       /* Next the normal addresses.  */
236       for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
237         {
238           cache_add (addr_list_type, addresses, hst->h_length, data, total,
239                      data, 0, t, db, owner);
240           addresses += hst->h_length;
241         }
242
243       /* If necessary the IPv6 addresses.  */
244       if (addr_list_type == GETHOSTBYADDR)
245         for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
246           {
247             cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ, data, total,
248                        data, 0, t, db, owner);
249             addresses += IN6ADDRSZ;
250           }
251
252       /* Avoid adding names if more than one address is available.  See
253          above for more info.  */
254       if (hst->h_addr_list[1] == NULL)
255         {
256           /* If necessary add the key for this request.  */
257           if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
258             {
259               if (addr_list_type == GETHOSTBYADDR)
260                 cache_add (GETHOSTBYNAME, key_copy, req->key_len, data, total,
261                            data, 0, t, db, owner);
262               cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len, data,
263                          total, data, 0, t, db, owner);
264             }
265
266           /* And finally the name.  We mark this as the last entry.  */
267           if (addr_list_type == GETHOSTBYADDR)
268             cache_add (GETHOSTBYNAME, data->strdata, h_name_len, data, total,
269                        data, 0, t, db, owner);
270           cache_add (GETHOSTBYNAMEv6, data->strdata, h_name_len, data,
271                      total, data, 1, t, db, owner);
272         }
273
274       pthread_rwlock_unlock (&db->lock);
275     }
276
277   if (__builtin_expect (written != total, 0) && debug_level > 0)
278     {
279       char buf[256];
280       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
281                strerror_r (errno, buf, sizeof (buf)));
282     }
283 }
284
285
286 void
287 addhstbyname (struct database *db, int fd, request_header *req,
288               void *key, uid_t uid)
289 {
290   /* Search for the entry matching the key.  Please note that we don't
291      look again in the table whether the dataset is now available.  We
292      simply insert it.  It does not matter if it is in there twice.  The
293      pruning function only will look at the timestamp.  */
294   int buflen = 1024;
295   char *buffer = (char *) alloca (buflen);
296   struct hostent resultbuf;
297   struct hostent *hst;
298   uid_t oldeuid = 0;
299   bool use_malloc = false;
300
301   if (__builtin_expect (debug_level > 0, 0))
302     dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
303
304   if (secure[hstdb])
305     {
306       oldeuid = geteuid ();
307       seteuid (uid);
308     }
309
310   while (__gethostbyname2_r (key, AF_INET, &resultbuf, buffer, buflen,
311                              &hst, &h_errno) != 0
312          && h_errno == NETDB_INTERNAL
313          && errno == ERANGE)
314     {
315       char *old_buffer = buffer;
316       errno = 0;
317       buflen += 1024;
318
319       if (__builtin_expect (buflen > 32768, 0))
320         {
321           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
322           if (buffer == NULL)
323             {
324               /* We ran out of memory.  We cannot do anything but
325                  sending a negative response.  In reality this should
326                  never happen.  */
327               hst = NULL;
328               buffer = old_buffer;
329               break;
330             }
331           use_malloc = true;
332         }
333       else
334         {
335           buffer = (char *) alloca (buflen);
336 #if _STACK_GROWS_DOWN
337           if (buffer + buflen == old_buffer)
338             buflen = 2 * buflen - 1024;
339 #elif _STACK_GROWS_UP
340           if (old_buffer + buflen - 1024 == buffer)
341             {
342               buffer = old_buffer;
343               buflen = 2 * buflen - 1024;
344             }
345 #endif
346         }
347     }
348
349   if (secure[hstdb])
350     seteuid (oldeuid);
351
352   cache_addhst (db, fd, req, key, hst, uid);
353
354   if (use_malloc)
355     free (buffer);
356 }
357
358
359 void
360 addhstbyaddr (struct database *db, int fd, request_header *req,
361               void *key, uid_t uid)
362 {
363   /* Search for the entry matching the key.  Please note that we don't
364      look again in the table whether the dataset is now available.  We
365      simply insert it.  It does not matter if it is in there twice.  The
366      pruning function only will look at the timestamp.  */
367   int buflen = 1024;
368   char *buffer = (char *) alloca (buflen);
369   struct hostent resultbuf;
370   struct hostent *hst;
371   uid_t oldeuid = 0;
372   bool use_malloc = false;
373
374   if (__builtin_expect (debug_level > 0, 0))
375     {
376       char buf[INET_ADDRSTRLEN];
377       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
378                inet_ntop (AF_INET, key, buf, sizeof (buf)));
379     }
380
381   if (secure[hstdb])
382     {
383       oldeuid = geteuid ();
384       seteuid (uid);
385     }
386
387   while (__gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, &resultbuf, buffer,
388                             buflen, &hst, &h_errno) != 0
389          && h_errno == NETDB_INTERNAL
390          && errno == ERANGE)
391     {
392       char *old_buffer = buffer;
393       errno = 0;
394       buflen += 1024;
395
396       if (__builtin_expect (buflen > 32768, 0))
397         {
398           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
399           if (buffer == NULL)
400             {
401               /* We ran out of memory.  We cannot do anything but
402                  sending a negative response.  In reality this should
403                  never happen.  */
404               hst = NULL;
405               buffer = old_buffer;
406               break;
407             }
408           use_malloc = true;
409         }
410       else
411         {
412           buffer = (char *) alloca (buflen);
413 #if _STACK_GROWS_DOWN
414           if (buffer + buflen == old_buffer)
415             buflen = 2 * buflen - 1024;
416 #elif _STACK_GROWS_UP
417           if (old_buffer + buflen - 1024 == buffer)
418             {
419               buffer = old_buffer;
420               buflen = 2 * buflen - 1024;
421             }
422 #endif
423         }
424     }
425
426   if (secure[hstdb])
427     seteuid (oldeuid);
428
429   cache_addhst (db, fd, req, key, hst, uid);
430
431   if (use_malloc)
432     free (buffer);
433 }
434
435
436 void
437 addhstbynamev6 (struct database *db, int fd, request_header *req,
438                 void *key, uid_t uid)
439 {
440   /* Search for the entry matching the key.  Please note that we don't
441      look again in the table whether the dataset is now available.  We
442      simply insert it.  It does not matter if it is in there twice.  The
443      pruning function only will look at the timestamp.  */
444   int buflen = 1024;
445   char *buffer = (char *) alloca (buflen);
446   struct hostent resultbuf;
447   struct hostent *hst;
448   uid_t oldeuid = 0;
449   bool use_malloc = false;
450
451   if (__builtin_expect (debug_level > 0, 0))
452     {
453       char buf[INET6_ADDRSTRLEN];
454
455       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
456                inet_ntop (AF_INET6, key, buf, sizeof (buf)));
457     }
458
459   if (secure[hstdb])
460     {
461       oldeuid = geteuid ();
462       seteuid (uid);
463     }
464
465   while (__gethostbyname2_r (key, AF_INET6, &resultbuf, buffer, buflen,
466                              &hst, &h_errno) != 0
467          && h_errno == NETDB_INTERNAL
468          && errno == ERANGE)
469     {
470       char *old_buffer = buffer;
471       errno = 0;
472       buflen += 1024;
473
474       if (__builtin_expect (buflen > 32768, 0))
475         {
476           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
477           if (buffer == NULL)
478             {
479               /* We ran out of memory.  We cannot do anything but
480                  sending a negative response.  In reality this should
481                  never happen.  */
482               hst = NULL;
483               buffer = old_buffer;
484               break;
485             }
486           use_malloc = true;
487         }
488       else
489         {
490           buffer = (char *) alloca (buflen);
491 #if _STACK_GROWS_DOWN
492           if (buffer + buflen == old_buffer)
493             buflen = 2 * buflen - 1024;
494 #elif _STACK_GROWS_UP
495           if (old_buffer + buflen - 1024 == buffer)
496             {
497               buffer = old_buffer;
498               buflen = 2 * buflen - 1024;
499             }
500 #endif
501         }
502     }
503
504   if (secure[hstdb])
505     seteuid (oldeuid);
506
507   cache_addhst (db, fd, req, key, hst, uid);
508
509   if (use_malloc)
510     free (buffer);
511 }
512
513
514 void
515 addhstbyaddrv6 (struct database *db, int fd, request_header *req,
516                 void *key, uid_t uid)
517 {
518   /* Search for the entry matching the key.  Please note that we don't
519      look again in the table whether the dataset is now available.  We
520      simply insert it.  It does not matter if it is in there twice.  The
521      pruning function only will look at the timestamp.  */
522   int buflen = 1024;
523   char *buffer = (char *) alloca (buflen);
524   struct hostent resultbuf;
525   struct hostent *hst;
526   uid_t oldeuid = 0;
527   bool use_malloc = false;
528
529   if (__builtin_expect (debug_level > 0, 0))
530     {
531       char buf[INET6_ADDRSTRLEN];
532       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
533                inet_ntop (AF_INET6, key, buf, sizeof (buf)));
534     }
535
536   if (secure[hstdb])
537     {
538       oldeuid = geteuid ();
539       seteuid (uid);
540     }
541
542   while (__gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, &resultbuf,
543                             buffer, buflen, &hst, &h_errno) != 0
544          && h_errno == NETDB_INTERNAL
545          && errno == ERANGE)
546     {
547       char *old_buffer = buffer;
548       errno = 0;
549       buflen += 1024;
550
551       if (__builtin_expect (buflen > 32768, 0))
552         {
553           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
554           if (buffer == NULL)
555             {
556               /* We ran out of memory.  We cannot do anything but
557                  sending a negative response.  In reality this should
558                  never happen.  */
559               hst = NULL;
560               buffer = old_buffer;
561               break;
562             }
563           use_malloc = true;
564         }
565       else
566         {
567           buffer = (char *) alloca (buflen);
568 #if _STACK_GROWS_DOWN
569           if (buffer + buflen == old_buffer)
570             buflen = 2 * buflen - 1024;
571 #elif _STACK_GROWS_UP
572           if (old_buffer + buflen - 1024 == buffer)
573             {
574               buffer = old_buffer;
575               buflen = 2 * buflen - 1024;
576             }
577 #endif
578         }
579     }
580
581   if (secure[hstdb])
582     seteuid (oldeuid);
583
584   cache_addhst (db, fd, req, key, hst, uid);
585
586   if (use_malloc)
587     free (buffer);
588 }