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.found = 1;
171       data->resp.h_name_len = h_name_len;
172       data->resp.h_aliases_cnt = h_aliases_cnt;
173       data->resp.h_addrtype = hst->h_addrtype;
174       data->resp.h_length = hst->h_length;
175       data->resp.h_addr_list_cnt = h_addr_list_cnt;
176       data->resp.error = NETDB_SUCCESS;
177
178       cp = data->strdata;
179
180       cp = mempcpy (cp, hst->h_name, h_name_len);
181       cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
182
183       /* The normal addresses first.  */
184       addresses = cp;
185       for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
186         cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
187
188       /* Then the aliases.  */
189       aliases = cp;
190       for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
191         cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
192
193       assert (cp == data->strdata + total - sizeof (hst_response_header));
194
195       /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
196          that the answer we get from the NSS does not contain the key
197          itself.  This is the case if the resolver is used and the name
198          is extended by the domainnames from /etc/resolv.conf.  Therefore
199          we explicitly add the name here.  */
200       if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
201         key_copy = memcpy (cp, key, req->key_len);
202
203       /* We write the dataset before inserting it to the database
204          since while inserting this thread might block and so would
205          unnecessarily let the receiver wait.  */
206       written = TEMP_FAILURE_RETRY (write (fd, data, total));
207
208       addr_list_type = (hst->h_length == NS_INADDRSZ
209                         ? GETHOSTBYADDR : GETHOSTBYADDRv6);
210
211       /* Compute the timeout time.  */
212       t += db->postimeout;
213
214       /* Now get the lock to safely insert the records.  */
215       pthread_rwlock_rdlock (&db->lock);
216
217       /* First add all the aliases.  If the record contains more than
218          one IP address (used for load balancing etc) don't cache the
219          entry.  This is something the current cache handling cannot
220          handle and it is more than questionable whether it is
221          worthwhile complicating the cache handling just for handling
222          such a special case.  */
223       if (!add_addr && hst->h_addr_list[1] == NULL)
224         for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
225           {
226             if (addr_list_type == GETHOSTBYADDR)
227               cache_add (GETHOSTBYNAME, aliases, h_aliases_len[cnt], data,
228                          total, data, 0, t, db, owner);
229
230             cache_add (GETHOSTBYNAMEv6, aliases, h_aliases_len[cnt], data,
231                        total, data, 0, t, db, owner);
232
233             aliases += h_aliases_len[cnt];
234           }
235
236       /* Next the normal addresses.  */
237       if (add_addr)
238         for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
239           {
240             cache_add (addr_list_type, addresses, hst->h_length, data, total,
241                        data, 0, t, db, owner);
242             addresses += hst->h_length;
243           }
244
245       /* If necessary the IPv6 addresses.  */
246       if (add_addr && addr_list_type == GETHOSTBYADDR)
247         for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
248           {
249             cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ, data, total,
250                        data, 0, t, db, owner);
251             addresses += IN6ADDRSZ;
252           }
253
254       /* Avoid adding names if more than one address is available.  See
255          above for more info.  */
256       if (!add_addr && hst->h_addr_list[1] == NULL)
257         {
258           /* If necessary add the key for this request.  */
259           if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
260             {
261               if (addr_list_type == GETHOSTBYADDR)
262                 cache_add (GETHOSTBYNAME, key_copy, req->key_len, data, total,
263                            data, 0, t, db, owner);
264               cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len, data,
265                          total, data, 0, t, db, owner);
266             }
267
268           /* And finally the name.  We mark this as the last entry.  */
269           if (addr_list_type == GETHOSTBYADDR)
270             cache_add (GETHOSTBYNAME, data->strdata, h_name_len, data, total,
271                        data, 0, t, db, owner);
272           cache_add (GETHOSTBYNAMEv6, data->strdata, h_name_len, data,
273                      total, data, 1, t, db, owner);
274         }
275
276       pthread_rwlock_unlock (&db->lock);
277     }
278
279   if (__builtin_expect (written != total, 0) && debug_level > 0)
280     {
281       char buf[256];
282       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
283                strerror_r (errno, buf, sizeof (buf)));
284     }
285 }
286
287
288 void
289 addhstbyname (struct database *db, int fd, request_header *req,
290               void *key, uid_t uid)
291 {
292   /* Search for the entry matching the key.  Please note that we don't
293      look again in the table whether the dataset is now available.  We
294      simply insert it.  It does not matter if it is in there twice.  The
295      pruning function only will look at the timestamp.  */
296   int buflen = 1024;
297   char *buffer = (char *) alloca (buflen);
298   struct hostent resultbuf;
299   struct hostent *hst;
300   uid_t oldeuid = 0;
301   bool use_malloc = false;
302
303   if (__builtin_expect (debug_level > 0, 0))
304     dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
305
306   if (secure[hstdb])
307     {
308       oldeuid = geteuid ();
309       seteuid (uid);
310     }
311
312   while (__gethostbyname2_r (key, AF_INET, &resultbuf, buffer, buflen,
313                              &hst, &h_errno) != 0
314          && h_errno == NETDB_INTERNAL
315          && errno == ERANGE)
316     {
317       char *old_buffer = buffer;
318       errno = 0;
319 #define INCR 1024
320
321       if (__builtin_expect (buflen > 32768, 0))
322         {
323           buflen += INCR;
324           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
325           if (buffer == NULL)
326             {
327               /* We ran out of memory.  We cannot do anything but
328                  sending a negative response.  In reality this should
329                  never happen.  */
330               hst = NULL;
331               buffer = old_buffer;
332               break;
333             }
334           use_malloc = true;
335         }
336       else
337         /* Allocate a new buffer on the stack.  If possible combine it
338            with the previously allocated buffer.  */
339         buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
340     }
341
342   if (secure[hstdb])
343     seteuid (oldeuid);
344
345   cache_addhst (db, fd, req, key, hst, uid, 0);
346
347   if (use_malloc)
348     free (buffer);
349 }
350
351
352 void
353 addhstbyaddr (struct database *db, int fd, request_header *req,
354               void *key, uid_t uid)
355 {
356   /* Search for the entry matching the key.  Please note that we don't
357      look again in the table whether the dataset is now available.  We
358      simply insert it.  It does not matter if it is in there twice.  The
359      pruning function only will look at the timestamp.  */
360   int buflen = 1024;
361   char *buffer = (char *) alloca (buflen);
362   struct hostent resultbuf;
363   struct hostent *hst;
364   uid_t oldeuid = 0;
365   bool use_malloc = false;
366
367   if (__builtin_expect (debug_level > 0, 0))
368     {
369       char buf[INET_ADDRSTRLEN];
370       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
371                inet_ntop (AF_INET, key, buf, sizeof (buf)));
372     }
373
374   if (secure[hstdb])
375     {
376       oldeuid = geteuid ();
377       seteuid (uid);
378     }
379
380   while (__gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, &resultbuf, buffer,
381                             buflen, &hst, &h_errno) != 0
382          && h_errno == NETDB_INTERNAL
383          && errno == ERANGE)
384     {
385       char *old_buffer = buffer;
386       errno = 0;
387
388       if (__builtin_expect (buflen > 32768, 0))
389         {
390           buflen += INCR;
391           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
392           if (buffer == NULL)
393             {
394               /* We ran out of memory.  We cannot do anything but
395                  sending a negative response.  In reality this should
396                  never happen.  */
397               hst = NULL;
398               buffer = old_buffer;
399               break;
400             }
401           use_malloc = true;
402         }
403       else
404         /* Allocate a new buffer on the stack.  If possible combine it
405            with the previously allocated buffer.  */
406         buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
407     }
408
409   if (secure[hstdb])
410     seteuid (oldeuid);
411
412   cache_addhst (db, fd, req, key, hst, uid, 1);
413
414   if (use_malloc)
415     free (buffer);
416 }
417
418
419 void
420 addhstbynamev6 (struct database *db, int fd, request_header *req,
421                 void *key, uid_t uid)
422 {
423   /* Search for the entry matching the key.  Please note that we don't
424      look again in the table whether the dataset is now available.  We
425      simply insert it.  It does not matter if it is in there twice.  The
426      pruning function only will look at the timestamp.  */
427   int buflen = 1024;
428   char *buffer = (char *) alloca (buflen);
429   struct hostent resultbuf;
430   struct hostent *hst;
431   uid_t oldeuid = 0;
432   bool use_malloc = false;
433
434   if (__builtin_expect (debug_level > 0, 0))
435     dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
436
437   if (secure[hstdb])
438     {
439       oldeuid = geteuid ();
440       seteuid (uid);
441     }
442
443   while (__gethostbyname2_r (key, AF_INET6, &resultbuf, buffer, buflen,
444                              &hst, &h_errno) != 0
445          && h_errno == NETDB_INTERNAL
446          && errno == ERANGE)
447     {
448       char *old_buffer = buffer;
449       errno = 0;
450
451       if (__builtin_expect (buflen > 32768, 0))
452         {
453           buflen += INCR;
454           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
455           if (buffer == NULL)
456             {
457               /* We ran out of memory.  We cannot do anything but
458                  sending a negative response.  In reality this should
459                  never happen.  */
460               hst = NULL;
461               buffer = old_buffer;
462               break;
463             }
464           use_malloc = true;
465         }
466       else
467         /* Allocate a new buffer on the stack.  If possible combine it
468            with the previously allocated buffer.  */
469         buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
470     }
471
472   if (secure[hstdb])
473     seteuid (oldeuid);
474
475   cache_addhst (db, fd, req, key, hst, uid, 0);
476
477   if (use_malloc)
478     free (buffer);
479 }
480
481
482 void
483 addhstbyaddrv6 (struct database *db, int fd, request_header *req,
484                 void *key, uid_t uid)
485 {
486   /* Search for the entry matching the key.  Please note that we don't
487      look again in the table whether the dataset is now available.  We
488      simply insert it.  It does not matter if it is in there twice.  The
489      pruning function only will look at the timestamp.  */
490   int buflen = 1024;
491   char *buffer = (char *) alloca (buflen);
492   struct hostent resultbuf;
493   struct hostent *hst;
494   uid_t oldeuid = 0;
495   bool use_malloc = false;
496
497   if (__builtin_expect (debug_level > 0, 0))
498     {
499       char buf[INET6_ADDRSTRLEN];
500       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
501                inet_ntop (AF_INET6, key, buf, sizeof (buf)));
502     }
503
504   if (secure[hstdb])
505     {
506       oldeuid = geteuid ();
507       seteuid (uid);
508     }
509
510   while (__gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, &resultbuf,
511                             buffer, buflen, &hst, &h_errno) != 0
512          && h_errno == NETDB_INTERNAL
513          && errno == ERANGE)
514     {
515       char *old_buffer = buffer;
516       errno = 0;
517
518       if (__builtin_expect (buflen > 32768, 0))
519         {
520           buflen += INCR;
521           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
522           if (buffer == NULL)
523             {
524               /* We ran out of memory.  We cannot do anything but
525                  sending a negative response.  In reality this should
526                  never happen.  */
527               hst = NULL;
528               buffer = old_buffer;
529               break;
530             }
531           use_malloc = true;
532         }
533       else
534         /* Allocate a new buffer on the stack.  If possible combine it
535            with the previously allocated buffer.  */
536         buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
537     }
538
539   if (secure[hstdb])
540     seteuid (oldeuid);
541
542   cache_addhst (db, fd, req, key, hst, uid, 1);
543
544   if (use_malloc)
545     free (buffer);
546 }