Merge branch 'master' of ssh://sourceware.org/git/glibc
[platform/upstream/glibc.git] / nscd / grpcache.c
1 /* Cache handling for group lookup.
2    Copyright (C) 1998-2008, 2009, 2011 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 time_t
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 *const 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   time_t timeout = MAX_TIMEOUT_VALUE;
95   if (grp == NULL)
96     {
97       if (he != NULL && errval == EAGAIN)
98         {
99           /* If we have an old record available but cannot find one
100              now because the service is not available we keep the old
101              record and make sure it does not get removed.  */
102           if (reload_count != UINT_MAX)
103             /* Do not reset the value if we never not reload the record.  */
104             dh->nreloads = reload_count - 1;
105
106           /* Reload with the same time-to-live value.  */
107           timeout = dh->timeout = t + db->postimeout;
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           total = sizeof (notfound);
116
117           if (fd != -1)
118             written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
119                                                 MSG_NOSIGNAL));
120
121           dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len,
122                                    1);
123           /* If we cannot permanently store the result, so be it.  */
124           if (dataset != NULL)
125             {
126               dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
127               dataset->head.recsize = total;
128               dataset->head.notfound = true;
129               dataset->head.nreloads = 0;
130               dataset->head.usable = true;
131
132               /* Compute the timeout time.  */
133               timeout = dataset->head.timeout = t + db->negtimeout;
134
135               /* This is the reply.  */
136               memcpy (&dataset->resp, &notfound, total);
137
138               /* Copy the key data.  */
139               memcpy (dataset->strdata, key, req->key_len);
140
141               /* If necessary, we also propagate the data to disk.  */
142               if (db->persistent)
143                 {
144                   // XXX async OK?
145                   uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
146                   msync ((void *) pval,
147                          ((uintptr_t) dataset & pagesize_m1)
148                          + sizeof (struct dataset) + req->key_len, MS_ASYNC);
149                 }
150
151               (void) cache_add (req->type, &dataset->strdata, req->key_len,
152                                 &dataset->head, true, db, owner, he == NULL);
153
154               pthread_rwlock_unlock (&db->lock);
155
156               /* Mark the old entry as obsolete.  */
157               if (dh != NULL)
158                 dh->usable = false;
159             }
160         }
161     }
162   else
163     {
164       /* Determine the I/O structure.  */
165       size_t gr_name_len = strlen (grp->gr_name) + 1;
166       size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
167       size_t gr_mem_cnt = 0;
168       uint32_t *gr_mem_len;
169       size_t gr_mem_len_total = 0;
170       char *gr_name;
171       char *cp;
172       const size_t key_len = strlen (key);
173       const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
174       char *buf = alloca (buf_len);
175       ssize_t n;
176       size_t cnt;
177
178       /* We need this to insert the `bygid' entry.  */
179       int key_offset;
180       n = snprintf (buf, buf_len, "%d%c%n%s", grp->gr_gid, '\0',
181                     &key_offset, (char *) key) + 1;
182
183       /* Determine the length of all members.  */
184       while (grp->gr_mem[gr_mem_cnt])
185         ++gr_mem_cnt;
186       gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
187       for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
188         {
189           gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
190           gr_mem_len_total += gr_mem_len[gr_mem_cnt];
191         }
192
193       written = total = (offsetof (struct dataset, strdata)
194                          + gr_mem_cnt * sizeof (uint32_t)
195                          + gr_name_len + gr_passwd_len + gr_mem_len_total);
196
197       /* If we refill the cache, first assume the reconrd did not
198          change.  Allocate memory on the cache since it is likely
199          discarded anyway.  If it turns out to be necessary to have a
200          new record we can still allocate real memory.  */
201       bool alloca_used = false;
202       dataset = NULL;
203
204       if (he == NULL)
205         dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
206
207       if (dataset == NULL)
208         {
209           /* We cannot permanently add the result in the moment.  But
210              we can provide the result as is.  Store the data in some
211              temporary memory.  */
212           dataset = (struct dataset *) alloca (total + n);
213
214           /* We cannot add this record to the permanent database.  */
215           alloca_used = true;
216         }
217
218       dataset->head.allocsize = total + n;
219       dataset->head.recsize = total - offsetof (struct dataset, resp);
220       dataset->head.notfound = false;
221       dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
222       dataset->head.usable = true;
223
224       /* Compute the timeout time.  */
225       timeout = dataset->head.timeout = t + db->postimeout;
226
227       dataset->resp.version = NSCD_VERSION;
228       dataset->resp.found = 1;
229       dataset->resp.gr_name_len = gr_name_len;
230       dataset->resp.gr_passwd_len = gr_passwd_len;
231       dataset->resp.gr_gid = grp->gr_gid;
232       dataset->resp.gr_mem_cnt = gr_mem_cnt;
233
234       cp = dataset->strdata;
235
236       /* This is the member string length array.  */
237       cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
238       gr_name = cp;
239       cp = mempcpy (cp, grp->gr_name, gr_name_len);
240       cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
241
242       for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
243         cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
244
245       /* Finally the stringified GID value.  */
246       memcpy (cp, buf, n);
247       char *key_copy = cp + key_offset;
248       assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
249
250       assert (cp == dataset->strdata + total - offsetof (struct dataset,
251                                                          strdata));
252
253       /* Now we can determine whether on refill we have to create a new
254          record or not.  */
255       if (he != NULL)
256         {
257           assert (fd == -1);
258
259           if (total + n == dh->allocsize
260               && total - offsetof (struct dataset, resp) == dh->recsize
261               && memcmp (&dataset->resp, dh->data,
262                          dh->allocsize - offsetof (struct dataset, resp)) == 0)
263             {
264               /* The data has not changed.  We will just bump the
265                  timeout value.  Note that the new record has been
266                  allocated on the stack and need not be freed.  */
267               dh->timeout = dataset->head.timeout;
268               ++dh->nreloads;
269             }
270           else
271             {
272               /* We have to create a new record.  Just allocate
273                  appropriate memory and copy it.  */
274               struct dataset *newp
275                 = (struct dataset *) mempool_alloc (db, total + n, 1);
276               if (newp != NULL)
277                 {
278                   /* Adjust pointers into the memory block.  */
279                   gr_name = (char *) newp + (gr_name - (char *) dataset);
280                   cp = (char *) newp + (cp - (char *) dataset);
281                   key_copy = (char *) newp + (key_copy - (char *) dataset);
282
283                   dataset = memcpy (newp, dataset, total + n);
284                   alloca_used = false;
285                 }
286
287               /* Mark the old record as obsolete.  */
288               dh->usable = false;
289             }
290         }
291       else
292         {
293           /* We write the dataset before inserting it to the database
294              since while inserting this thread might block and so would
295              unnecessarily let the receiver wait.  */
296           assert (fd != -1);
297
298 #ifdef HAVE_SENDFILE
299           if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
300             {
301               assert (db->wr_fd != -1);
302               assert ((char *) &dataset->resp > (char *) db->data);
303               assert ((char *) dataset - (char *) db->head
304                       + total
305                       <= (sizeof (struct database_pers_head)
306                           + db->head->module * sizeof (ref_t)
307                           + db->head->data_size));
308               written = sendfileall (fd, db->wr_fd,
309                                      (char *) &dataset->resp
310                                      - (char *) db->head, dataset->head.recsize);
311 # ifndef __ASSUME_SENDFILE
312               if (written == -1 && errno == ENOSYS)
313                 goto use_write;
314 # endif
315             }
316           else
317 # ifndef __ASSUME_SENDFILE
318           use_write:
319 # endif
320 #endif
321             written = writeall (fd, &dataset->resp, dataset->head.recsize);
322         }
323
324       /* Add the record to the database.  But only if it has not been
325          stored on the stack.  */
326       if (! alloca_used)
327         {
328           /* If necessary, we also propagate the data to disk.  */
329           if (db->persistent)
330             {
331               // XXX async OK?
332               uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
333               msync ((void *) pval,
334                      ((uintptr_t) dataset & pagesize_m1) + total + n,
335                      MS_ASYNC);
336             }
337
338           /* NB: in the following code we always must add the entry
339              marked with FIRST first.  Otherwise we end up with
340              dangling "pointers" in case a latter hash entry cannot be
341              added.  */
342           bool first = true;
343
344           /* If the request was by GID, add that entry first.  */
345           if (req->type == GETGRBYGID)
346             {
347               if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
348                              db, owner, he == NULL) < 0)
349                 goto out;
350
351               first = false;
352             }
353           /* If the key is different from the name add a separate entry.  */
354           else if (strcmp (key_copy, gr_name) != 0)
355             {
356               if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
357                              &dataset->head, true, db, owner, he == NULL) < 0)
358                 goto out;
359
360               first = false;
361             }
362
363           /* We have to add the value for both, byname and byuid.  */
364           if ((req->type == GETGRBYNAME || db->propagate)
365               && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
366                                               gr_name_len,
367                                               &dataset->head, first, db, owner,
368                                               he == NULL)
369                                    == 0, 1))
370             {
371               if (req->type == GETGRBYNAME && db->propagate)
372                 (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
373                                   false, db, owner, false);
374             }
375
376         out:
377           pthread_rwlock_unlock (&db->lock);
378         }
379     }
380
381   if (__builtin_expect (written != total, 0) && debug_level > 0)
382     {
383       char buf[256];
384       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
385                strerror_r (errno, buf, sizeof (buf)));
386     }
387
388   return timeout;
389 }
390
391
392 union keytype
393 {
394   void *v;
395   gid_t g;
396 };
397
398
399 static int
400 lookup (int type, union keytype key, struct group *resultbufp, char *buffer,
401         size_t buflen, struct group **grp)
402 {
403   if (type == GETGRBYNAME)
404     return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp);
405   else
406     return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp);
407 }
408
409
410 static time_t
411 addgrbyX (struct database_dyn *db, int fd, request_header *req,
412           union keytype key, const char *keystr, uid_t uid,
413           struct hashentry *he, struct datahead *dh)
414 {
415   /* Search for the entry matching the key.  Please note that we don't
416      look again in the table whether the dataset is now available.  We
417      simply insert it.  It does not matter if it is in there twice.  The
418      pruning function only will look at the timestamp.  */
419   size_t buflen = 1024;
420   char *buffer = (char *) alloca (buflen);
421   struct group resultbuf;
422   struct group *grp;
423   bool use_malloc = false;
424   int errval = 0;
425
426   if (__builtin_expect (debug_level > 0, 0))
427     {
428       if (he == NULL)
429         dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
430       else
431         dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
432     }
433
434   while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
435          && (errval = errno) == ERANGE)
436     {
437       errno = 0;
438
439       if (__builtin_expect (buflen > 32768, 0))
440         {
441           char *old_buffer = buffer;
442           buflen *= 2;
443           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
444           if (buffer == NULL)
445             {
446               /* We ran out of memory.  We cannot do anything but
447                  sending a negative response.  In reality this should
448                  never happen.  */
449               grp = NULL;
450               buffer = old_buffer;
451
452               /* We set the error to indicate this is (possibly) a
453                  temporary error and that it does not mean the entry
454                  is not available at all.  */
455               errval = EAGAIN;
456               break;
457             }
458           use_malloc = true;
459         }
460       else
461         /* Allocate a new buffer on the stack.  If possible combine it
462            with the previously allocated buffer.  */
463         buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
464     }
465
466   time_t timeout = cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
467
468   if (use_malloc)
469     free (buffer);
470
471   return timeout;
472 }
473
474
475 void
476 addgrbyname (struct database_dyn *db, int fd, request_header *req,
477              void *key, uid_t uid)
478 {
479   union keytype u = { .v = key };
480
481   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
482 }
483
484
485 time_t
486 readdgrbyname (struct database_dyn *db, struct hashentry *he,
487                struct datahead *dh)
488 {
489   request_header req =
490     {
491       .type = GETGRBYNAME,
492       .key_len = he->len
493     };
494   union keytype u = { .v = db->data + he->key };
495
496   return addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
497 }
498
499
500 void
501 addgrbygid (struct database_dyn *db, int fd, request_header *req,
502             void *key, uid_t uid)
503 {
504   char *ep;
505   gid_t gid = strtoul ((char *) key, &ep, 10);
506
507   if (*(char *) key == '\0' || *ep != '\0')  /* invalid numeric uid */
508     {
509       if (debug_level > 0)
510         dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
511
512       errno = EINVAL;
513       return;
514     }
515
516   union keytype u = { .g = gid };
517
518   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
519 }
520
521
522 time_t
523 readdgrbygid (struct database_dyn *db, struct hashentry *he,
524               struct datahead *dh)
525 {
526   char *ep;
527   gid_t gid = strtoul (db->data + he->key, &ep, 10);
528
529   /* Since the key has been added before it must be OK.  */
530   assert (*(db->data + he->key) != '\0' && *ep == '\0');
531
532   request_header req =
533     {
534       .type = GETGRBYGID,
535       .key_len = he->len
536     };
537   union keytype u = { .g = gid };
538
539   return addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
540 }