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