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