Replace lll_private_futex_* (*) with lll_futex_* (*, LLL_PRIVATE).
[kopensolaris-gnu/glibc.git] / nscd / grpcache.c
1 /* Cache handling for group lookup.
2    Copyright (C) 1998-2005, 2006, 2007 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    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published
8    by the Free Software Foundation; version 2 of the License, or
9    (at your option) any later version.
10
11    This program 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
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include <alloca.h>
21 #include <assert.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <grp.h>
25 #include <libintl.h>
26 #include <stdbool.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <stackinfo.h>
36
37 #include "nscd.h"
38 #include "dbg_log.h"
39 #ifdef HAVE_SENDFILE
40 # include <kernel-features.h>
41 #endif
42
43 /* This is the standard reply in case the service is disabled.  */
44 static const gr_response_header disabled =
45 {
46   .version = NSCD_VERSION,
47   .found = -1,
48   .gr_name_len = 0,
49   .gr_passwd_len = 0,
50   .gr_gid = -1,
51   .gr_mem_cnt = 0,
52 };
53
54 /* This is the struct describing how to write this record.  */
55 const struct iovec grp_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 gr_response_header notfound =
64 {
65   .version = NSCD_VERSION,
66   .found = 0,
67   .gr_name_len = 0,
68   .gr_passwd_len = 0,
69   .gr_gid = -1,
70   .gr_mem_cnt = 0,
71 };
72
73
74 static void
75 cache_addgr (struct database_dyn *db, int fd, request_header *req,
76              const void *key, struct group *grp, uid_t owner,
77              struct hashentry *he, struct datahead *dh, int errval)
78 {
79   ssize_t total;
80   ssize_t written;
81   time_t t = time (NULL);
82
83   /* We allocate all data in one memory block: the iov vector,
84      the response header and the dataset itself.  */
85   struct dataset
86   {
87     struct datahead head;
88     gr_response_header resp;
89     char strdata[0];
90   } *dataset;
91
92   assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
93
94   if (grp == NULL)
95     {
96       if (he != NULL && errval == EAGAIN)
97         {
98           /* If we have an old record available but cannot find one
99              now because the service is not available we keep the old
100              record and make sure it does not get removed.  */
101           if (reload_count != UINT_MAX)
102             /* Do not reset the value if we never not reload the record.  */
103             dh->nreloads = reload_count - 1;
104
105           written = total = 0;
106         }
107       else
108         {
109           /* We have no data.  This means we send the standard reply for this
110              case.  */
111           total = sizeof (notfound);
112
113           written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
114                                               MSG_NOSIGNAL));
115
116           dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
117           /* If we cannot permanently store the result, so be it.  */
118           if (dataset != NULL)
119             {
120               dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
121               dataset->head.recsize = total;
122               dataset->head.notfound = true;
123               dataset->head.nreloads = 0;
124               dataset->head.usable = true;
125
126               /* Compute the timeout time.  */
127               dataset->head.timeout = t + db->negtimeout;
128
129               /* This is the reply.  */
130               memcpy (&dataset->resp, &notfound, total);
131
132               /* Copy the key data.  */
133               memcpy (dataset->strdata, key, req->key_len);
134
135               /* If necessary, we also propagate the data to disk.  */
136               if (db->persistent)
137                 {
138                   // XXX async OK?
139                   uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
140                   msync ((void *) pval,
141                          ((uintptr_t) dataset & pagesize_m1)
142                          + sizeof (struct dataset) + req->key_len, MS_ASYNC);
143                 }
144
145               /* Now get the lock to safely insert the records.  */
146               pthread_rwlock_rdlock (&db->lock);
147
148               if (cache_add (req->type, &dataset->strdata, req->key_len,
149                              &dataset->head, true, db, owner) < 0)
150                 /* Ensure the data can be recovered.  */
151                 dataset->head.usable = false;
152
153               pthread_rwlock_unlock (&db->lock);
154
155               /* Mark the old entry as obsolete.  */
156               if (dh != NULL)
157                 dh->usable = false;
158             }
159           else
160             ++db->head->addfailed;
161         }
162     }
163   else
164     {
165       /* Determine the I/O structure.  */
166       size_t gr_name_len = strlen (grp->gr_name) + 1;
167       size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
168       size_t gr_mem_cnt = 0;
169       uint32_t *gr_mem_len;
170       size_t gr_mem_len_total = 0;
171       char *gr_name;
172       char *cp;
173       const size_t key_len = strlen (key);
174       const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
175       char *buf = alloca (buf_len);
176       ssize_t n;
177       size_t cnt;
178
179       /* We need this to insert the `bygid' entry.  */
180       int key_offset;
181       n = snprintf (buf, buf_len, "%d%c%n%s", grp->gr_gid, '\0',
182                     &key_offset, (char *) key) + 1;
183
184       /* Determine the length of all members.  */
185       while (grp->gr_mem[gr_mem_cnt])
186         ++gr_mem_cnt;
187       gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
188       for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
189         {
190           gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
191           gr_mem_len_total += gr_mem_len[gr_mem_cnt];
192         }
193
194       written = total = (sizeof (struct dataset)
195                          + gr_mem_cnt * sizeof (uint32_t)
196                          + gr_name_len + gr_passwd_len + gr_mem_len_total);
197
198       /* If we refill the cache, first assume the reconrd did not
199          change.  Allocate memory on the cache since it is likely
200          discarded anyway.  If it turns out to be necessary to have a
201          new record we can still allocate real memory.  */
202       bool alloca_used = false;
203       dataset = NULL;
204
205       if (he == NULL)
206         {
207           dataset = (struct dataset *) mempool_alloc (db, total + n);
208           if (dataset == NULL)
209             ++db->head->addfailed;
210         }
211
212       if (dataset == NULL)
213         {
214           /* We cannot permanently add the result in the moment.  But
215              we can provide the result as is.  Store the data in some
216              temporary memory.  */
217           dataset = (struct dataset *) alloca (total + n);
218
219           /* We cannot add this record to the permanent database.  */
220           alloca_used = true;
221         }
222
223       dataset->head.allocsize = total + n;
224       dataset->head.recsize = total - offsetof (struct dataset, resp);
225       dataset->head.notfound = false;
226       dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
227       dataset->head.usable = true;
228
229       /* Compute the timeout time.  */
230       dataset->head.timeout = t + db->postimeout;
231
232       dataset->resp.version = NSCD_VERSION;
233       dataset->resp.found = 1;
234       dataset->resp.gr_name_len = gr_name_len;
235       dataset->resp.gr_passwd_len = gr_passwd_len;
236       dataset->resp.gr_gid = grp->gr_gid;
237       dataset->resp.gr_mem_cnt = gr_mem_cnt;
238
239       cp = dataset->strdata;
240
241       /* This is the member string length array.  */
242       cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
243       gr_name = cp;
244       cp = mempcpy (cp, grp->gr_name, gr_name_len);
245       cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
246
247       for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
248         cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
249
250       /* Finally the stringified GID value.  */
251       memcpy (cp, buf, n);
252       char *key_copy = cp + key_offset;
253       assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
254
255       /* Now we can determine whether on refill we have to create a new
256          record or not.  */
257       if (he != NULL)
258         {
259           assert (fd == -1);
260
261           if (total + n == dh->allocsize
262               && total - offsetof (struct dataset, resp) == dh->recsize
263               && memcmp (&dataset->resp, dh->data,
264                          dh->allocsize - offsetof (struct dataset, resp)) == 0)
265             {
266               /* The data has not changed.  We will just bump the
267                  timeout value.  Note that the new record has been
268                  allocated on the stack and need not be freed.  */
269               dh->timeout = dataset->head.timeout;
270               ++dh->nreloads;
271             }
272           else
273             {
274               /* We have to create a new record.  Just allocate
275                  appropriate memory and copy it.  */
276               struct dataset *newp
277                 = (struct dataset *) mempool_alloc (db, total + n);
278               if (newp != NULL)
279                 {
280                   /* Adjust pointers into the memory block.  */
281                   gr_name = (char *) newp + (gr_name - (char *) dataset);
282                   cp = (char *) newp + (cp - (char *) dataset);
283                   key_copy = (char *) newp + (key_copy - (char *) dataset);
284
285                   dataset = memcpy (newp, dataset, total + n);
286                   alloca_used = false;
287                 }
288
289               /* Mark the old record as obsolete.  */
290               dh->usable = false;
291             }
292         }
293       else
294         {
295           /* We write the dataset before inserting it to the database
296              since while inserting this thread might block and so would
297              unnecessarily let the receiver wait.  */
298           assert (fd != -1);
299
300 #ifdef HAVE_SENDFILE
301           if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
302             {
303               assert (db->wr_fd != -1);
304               assert ((char *) &dataset->resp > (char *) db->data);
305               assert ((char *) &dataset->resp - (char *) db->head
306                       + total
307                       <= (sizeof (struct database_pers_head)
308                           + db->head->module * sizeof (ref_t)
309                           + db->head->data_size));
310               written = sendfileall (fd, db->wr_fd,
311                                      (char *) &dataset->resp
312                                      - (char *) db->head, total);
313 # ifndef __ASSUME_SENDFILE
314               if (written == -1 && errno == ENOSYS)
315                 goto use_write;
316 # endif
317             }
318           else
319 # ifndef __ASSUME_SENDFILE
320           use_write:
321 # endif
322 #endif
323             written = writeall (fd, &dataset->resp, total);
324         }
325
326       /* Add the record to the database.  But only if it has not been
327          stored on the stack.  */
328       if (! alloca_used)
329         {
330           /* If necessary, we also propagate the data to disk.  */
331           if (db->persistent)
332             {
333               // XXX async OK?
334               uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
335               msync ((void *) pval,
336                      ((uintptr_t) dataset & pagesize_m1) + total + n,
337                      MS_ASYNC);
338             }
339
340           /* Now get the lock to safely insert the records.  */
341           pthread_rwlock_rdlock (&db->lock);
342
343           /* NB: in the following code we always must add the entry
344              marked with FIRST first.  Otherwise we end up with
345              dangling "pointers" in case a latter hash entry cannot be
346              added.  */
347           bool first = true;
348
349           /* If the request was by GID, add that entry first.  */
350           if (req->type == GETGRBYGID)
351             {
352               if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
353                              db, owner) < 0)
354                 {
355                   /* Could not allocate memory.  Make sure the data gets
356                      discarded.  */
357                   dataset->head.usable = false;
358                   goto out;
359                 }
360
361               first = false;
362             }
363           /* If the key is different from the name add a separate entry.  */
364           else if (strcmp (key_copy, gr_name) != 0)
365             {
366               if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
367                              &dataset->head, true, db, owner) < 0)
368                 {
369                   /* Could not allocate memory.  Make sure the data gets
370                      discarded.  */
371                   dataset->head.usable = false;
372                   goto out;
373                 }
374
375               first = false;
376             }
377
378           /* We have to add the value for both, byname and byuid.  */
379           if ((req->type == GETGRBYNAME || db->propagate)
380               && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
381                                               gr_name_len,
382                                               &dataset->head, first, db, owner)
383                                    == 0, 1))
384             {
385               if (req->type == GETGRBYNAME && db->propagate)
386                 (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
387                                   req->type != GETGRBYNAME, db, owner);
388             }
389           else if (first)
390             /* Could not allocate memory.  Make sure the data gets
391                discarded.  */
392             dataset->head.usable = false;
393
394         out:
395           pthread_rwlock_unlock (&db->lock);
396         }
397     }
398
399   if (__builtin_expect (written != total, 0) && debug_level > 0)
400     {
401       char buf[256];
402       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
403                strerror_r (errno, buf, sizeof (buf)));
404     }
405 }
406
407
408 union keytype
409 {
410   void *v;
411   gid_t g;
412 };
413
414
415 static int
416 lookup (int type, union keytype key, struct group *resultbufp, char *buffer,
417         size_t buflen, struct group **grp)
418 {
419   if (type == GETGRBYNAME)
420     return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp);
421   else
422     return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp);
423 }
424
425
426 static void
427 addgrbyX (struct database_dyn *db, int fd, request_header *req,
428           union keytype key, const char *keystr, uid_t uid,
429           struct hashentry *he, struct datahead *dh)
430 {
431   /* Search for the entry matching the key.  Please note that we don't
432      look again in the table whether the dataset is now available.  We
433      simply insert it.  It does not matter if it is in there twice.  The
434      pruning function only will look at the timestamp.  */
435   size_t buflen = 1024;
436   char *buffer = (char *) alloca (buflen);
437   struct group resultbuf;
438   struct group *grp;
439   bool use_malloc = false;
440   int errval = 0;
441
442   if (__builtin_expect (debug_level > 0, 0))
443     {
444       if (he == NULL)
445         dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
446       else
447         dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
448     }
449
450   while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
451          && (errval = errno) == ERANGE)
452     {
453       errno = 0;
454
455       if (__builtin_expect (buflen > 32768, 0))
456         {
457           char *old_buffer = buffer;
458           buflen *= 2;
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               grp = 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, 2 * buflen);
480     }
481
482   cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
483
484   if (use_malloc)
485     free (buffer);
486 }
487
488
489 void
490 addgrbyname (struct database_dyn *db, int fd, request_header *req,
491              void *key, uid_t uid)
492 {
493   union keytype u = { .v = key };
494
495   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
496 }
497
498
499 void
500 readdgrbyname (struct database_dyn *db, struct hashentry *he,
501                struct datahead *dh)
502 {
503   request_header req =
504     {
505       .type = GETGRBYNAME,
506       .key_len = he->len
507     };
508   union keytype u = { .v = db->data + he->key };
509
510   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
511 }
512
513
514 void
515 addgrbygid (struct database_dyn *db, int fd, request_header *req,
516             void *key, uid_t uid)
517 {
518   char *ep;
519   gid_t gid = strtoul ((char *) key, &ep, 10);
520
521   if (*(char *) key == '\0' || *ep != '\0')  /* invalid numeric uid */
522     {
523       if (debug_level > 0)
524         dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
525
526       errno = EINVAL;
527       return;
528     }
529
530   union keytype u = { .g = gid };
531
532   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
533 }
534
535
536 void
537 readdgrbygid (struct database_dyn *db, struct hashentry *he,
538               struct datahead *dh)
539 {
540   char *ep;
541   gid_t gid = strtoul (db->data + he->key, &ep, 10);
542
543   /* Since the key has been added before it must be OK.  */
544   assert (*(db->data + he->key) != '\0' && *ep == '\0');
545
546   request_header req =
547     {
548       .type = GETGRBYGID,
549       .key_len = he->len
550     };
551   union keytype u = { .g = gid };
552
553   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
554 }