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