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