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, int add_addr)
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 (!add_addr && 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       if (add_addr)
237         for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
238           {
239             cache_add (addr_list_type, addresses, hst->h_length, data, total,
240                        data, 0, t, db, owner);
241             addresses += hst->h_length;
242           }
243
244       /* If necessary the IPv6 addresses.  */
245       if (add_addr && addr_list_type == GETHOSTBYADDR)
246         for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
247           {
248             cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ, data, total,
249                        data, 0, t, db, owner);
250             addresses += IN6ADDRSZ;
251           }
252
253       /* Avoid adding names if more than one address is available.  See
254          above for more info.  */
255       if (!add_addr && hst->h_addr_list[1] == NULL)
256         {
257           /* If necessary add the key for this request.  */
258           if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
259             {
260               if (addr_list_type == GETHOSTBYADDR)
261                 cache_add (GETHOSTBYNAME, key_copy, req->key_len, data, total,
262                            data, 0, t, db, owner);
263               cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len, data,
264                          total, data, 0, t, db, owner);
265             }
266
267           /* And finally the name.  We mark this as the last entry.  */
268           if (addr_list_type == GETHOSTBYADDR)
269             cache_add (GETHOSTBYNAME, data->strdata, h_name_len, data, total,
270                        data, 0, t, db, owner);
271           cache_add (GETHOSTBYNAMEv6, data->strdata, h_name_len, data,
272                      total, data, 1, t, db, owner);
273         }
274
275       pthread_rwlock_unlock (&db->lock);
276     }
277
278   if (__builtin_expect (written != total, 0) && debug_level > 0)
279     {
280       char buf[256];
281       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
282                strerror_r (errno, buf, sizeof (buf)));
283     }
284 }
285
286
287 void
288 addhstbyname (struct database *db, int fd, request_header *req,
289               void *key, uid_t uid)
290 {
291   /* Search for the entry matching the key.  Please note that we don't
292      look again in the table whether the dataset is now available.  We
293      simply insert it.  It does not matter if it is in there twice.  The
294      pruning function only will look at the timestamp.  */
295   int buflen = 1024;
296   char *buffer = (char *) alloca (buflen);
297   struct hostent resultbuf;
298   struct hostent *hst;
299   uid_t oldeuid = 0;
300   bool use_malloc = false;
301
302   if (__builtin_expect (debug_level > 0, 0))
303     dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
304
305   if (secure[hstdb])
306     {
307       oldeuid = geteuid ();
308       seteuid (uid);
309     }
310
311   while (__gethostbyname2_r (key, AF_INET, &resultbuf, buffer, buflen,
312                              &hst, &h_errno) != 0
313          && h_errno == NETDB_INTERNAL
314          && errno == ERANGE)
315     {
316       char *old_buffer = buffer;
317       errno = 0;
318       buflen += 1024;
319
320       if (__builtin_expect (buflen > 32768, 0))
321         {
322           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
323           if (buffer == NULL)
324             {
325               /* We ran out of memory.  We cannot do anything but
326                  sending a negative response.  In reality this should
327                  never happen.  */
328               hst = NULL;
329               buffer = old_buffer;
330               break;
331             }
332           use_malloc = true;
333         }
334       else
335         {
336           buffer = (char *) alloca (buflen);
337 #if _STACK_GROWS_DOWN
338           if (buffer + buflen == old_buffer)
339             buflen = 2 * buflen - 1024;
340 #elif _STACK_GROWS_UP
341           if (old_buffer + buflen - 1024 == buffer)
342             {
343               buffer = old_buffer;
344               buflen = 2 * buflen - 1024;
345             }
346 #endif
347         }
348     }
349
350   if (secure[hstdb])
351     seteuid (oldeuid);
352
353   cache_addhst (db, fd, req, key, hst, uid, 0);
354
355   if (use_malloc)
356     free (buffer);
357 }
358
359
360 void
361 addhstbyaddr (struct database *db, int fd, request_header *req,
362               void *key, uid_t uid)
363 {
364   /* Search for the entry matching the key.  Please note that we don't
365      look again in the table whether the dataset is now available.  We
366      simply insert it.  It does not matter if it is in there twice.  The
367      pruning function only will look at the timestamp.  */
368   int buflen = 1024;
369   char *buffer = (char *) alloca (buflen);
370   struct hostent resultbuf;
371   struct hostent *hst;
372   uid_t oldeuid = 0;
373   bool use_malloc = false;
374
375   if (__builtin_expect (debug_level > 0, 0))
376     {
377       char buf[INET_ADDRSTRLEN];
378       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
379                inet_ntop (AF_INET, key, buf, sizeof (buf)));
380     }
381
382   if (secure[hstdb])
383     {
384       oldeuid = geteuid ();
385       seteuid (uid);
386     }
387
388   while (__gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, &resultbuf, buffer,
389                             buflen, &hst, &h_errno) != 0
390          && h_errno == NETDB_INTERNAL
391          && errno == ERANGE)
392     {
393       char *old_buffer = buffer;
394       errno = 0;
395       buflen += 1024;
396
397       if (__builtin_expect (buflen > 32768, 0))
398         {
399           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
400           if (buffer == NULL)
401             {
402               /* We ran out of memory.  We cannot do anything but
403                  sending a negative response.  In reality this should
404                  never happen.  */
405               hst = NULL;
406               buffer = old_buffer;
407               break;
408             }
409           use_malloc = true;
410         }
411       else
412         {
413           buffer = (char *) alloca (buflen);
414 #if _STACK_GROWS_DOWN
415           if (buffer + buflen == old_buffer)
416             buflen = 2 * buflen - 1024;
417 #elif _STACK_GROWS_UP
418           if (old_buffer + buflen - 1024 == buffer)
419             {
420               buffer = old_buffer;
421               buflen = 2 * buflen - 1024;
422             }
423 #endif
424         }
425     }
426
427   if (secure[hstdb])
428     seteuid (oldeuid);
429
430   cache_addhst (db, fd, req, key, hst, uid, 1);
431
432   if (use_malloc)
433     free (buffer);
434 }
435
436
437 void
438 addhstbynamev6 (struct database *db, int fd, request_header *req,
439                 void *key, uid_t uid)
440 {
441   /* Search for the entry matching the key.  Please note that we don't
442      look again in the table whether the dataset is now available.  We
443      simply insert it.  It does not matter if it is in there twice.  The
444      pruning function only will look at the timestamp.  */
445   int buflen = 1024;
446   char *buffer = (char *) alloca (buflen);
447   struct hostent resultbuf;
448   struct hostent *hst;
449   uid_t oldeuid = 0;
450   bool use_malloc = false;
451
452   if (__builtin_expect (debug_level > 0, 0))
453     {
454       char buf[INET6_ADDRSTRLEN];
455
456       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
457                inet_ntop (AF_INET6, key, buf, sizeof (buf)));
458     }
459
460   if (secure[hstdb])
461     {
462       oldeuid = geteuid ();
463       seteuid (uid);
464     }
465
466   while (__gethostbyname2_r (key, AF_INET6, &resultbuf, buffer, buflen,
467                              &hst, &h_errno) != 0
468          && h_errno == NETDB_INTERNAL
469          && errno == ERANGE)
470     {
471       char *old_buffer = buffer;
472       errno = 0;
473       buflen += 1024;
474
475       if (__builtin_expect (buflen > 32768, 0))
476         {
477           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
478           if (buffer == NULL)
479             {
480               /* We ran out of memory.  We cannot do anything but
481                  sending a negative response.  In reality this should
482                  never happen.  */
483               hst = NULL;
484               buffer = old_buffer;
485               break;
486             }
487           use_malloc = true;
488         }
489       else
490         {
491           buffer = (char *) alloca (buflen);
492 #if _STACK_GROWS_DOWN
493           if (buffer + buflen == old_buffer)
494             buflen = 2 * buflen - 1024;
495 #elif _STACK_GROWS_UP
496           if (old_buffer + buflen - 1024 == buffer)
497             {
498               buffer = old_buffer;
499               buflen = 2 * buflen - 1024;
500             }
501 #endif
502         }
503     }
504
505   if (secure[hstdb])
506     seteuid (oldeuid);
507
508   cache_addhst (db, fd, req, key, hst, uid, 0);
509
510   if (use_malloc)
511     free (buffer);
512 }
513
514
515 void
516 addhstbyaddrv6 (struct database *db, int fd, request_header *req,
517                 void *key, uid_t uid)
518 {
519   /* Search for the entry matching the key.  Please note that we don't
520      look again in the table whether the dataset is now available.  We
521      simply insert it.  It does not matter if it is in there twice.  The
522      pruning function only will look at the timestamp.  */
523   int buflen = 1024;
524   char *buffer = (char *) alloca (buflen);
525   struct hostent resultbuf;
526   struct hostent *hst;
527   uid_t oldeuid = 0;
528   bool use_malloc = false;
529
530   if (__builtin_expect (debug_level > 0, 0))
531     {
532       char buf[INET6_ADDRSTRLEN];
533       dbg_log (_("Haven't found \"%s\" in hosts cache!"),
534                inet_ntop (AF_INET6, key, buf, sizeof (buf)));
535     }
536
537   if (secure[hstdb])
538     {
539       oldeuid = geteuid ();
540       seteuid (uid);
541     }
542
543   while (__gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, &resultbuf,
544                             buffer, buflen, &hst, &h_errno) != 0
545          && h_errno == NETDB_INTERNAL
546          && errno == ERANGE)
547     {
548       char *old_buffer = buffer;
549       errno = 0;
550       buflen += 1024;
551
552       if (__builtin_expect (buflen > 32768, 0))
553         {
554           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
555           if (buffer == NULL)
556             {
557               /* We ran out of memory.  We cannot do anything but
558                  sending a negative response.  In reality this should
559                  never happen.  */
560               hst = NULL;
561               buffer = old_buffer;
562               break;
563             }
564           use_malloc = true;
565         }
566       else
567         {
568           buffer = (char *) alloca (buflen);
569 #if _STACK_GROWS_DOWN
570           if (buffer + buflen == old_buffer)
571             buflen = 2 * buflen - 1024;
572 #elif _STACK_GROWS_UP
573           if (old_buffer + buflen - 1024 == buffer)
574             {
575               buffer = old_buffer;
576               buflen = 2 * buflen - 1024;
577             }
578 #endif
579         }
580     }
581
582   if (secure[hstdb])
583     seteuid (oldeuid);
584
585   cache_addhst (db, fd, req, key, hst, uid, 1);
586
587   if (use_malloc)
588     free (buffer);
589 }