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