.
[platform/upstream/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 version 2 as
8    published by the Free Software Foundation.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
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 void
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 *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   if (grp == NULL)
94     {
95       if (he != NULL && errval == EAGAIN)
96         {
97           /* If we have an old record available but cannot find one
98              now because the service is not available we keep the old
99              record and make sure it does not get removed.  */
100           if (reload_count != UINT_MAX)
101             /* Do not reset the value if we never not reload the record.  */
102             dh->nreloads = reload_count - 1;
103
104           written = total = 0;
105         }
106       else
107         {
108           /* We have no data.  This means we send the standard reply for this
109              case.  */
110           total = sizeof (notfound);
111
112           written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
113                                               MSG_NOSIGNAL));
114
115           dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
116           /* If we cannot permanently store the result, so be it.  */
117           if (dataset != NULL)
118             {
119               dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
120               dataset->head.recsize = total;
121               dataset->head.notfound = true;
122               dataset->head.nreloads = 0;
123               dataset->head.usable = true;
124
125               /* Compute the timeout time.  */
126               dataset->head.timeout = t + db->negtimeout;
127
128               /* This is the reply.  */
129               memcpy (&dataset->resp, &notfound, total);
130
131               /* Copy the key data.  */
132               memcpy (dataset->strdata, key, req->key_len);
133
134               /* If necessary, we also propagate the data to disk.  */
135               if (db->persistent)
136                 {
137                   // XXX async OK?
138                   uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
139                   msync ((void *) pval,
140                          ((uintptr_t) dataset & pagesize_m1)
141                          + sizeof (struct dataset) + req->key_len, MS_ASYNC);
142                 }
143
144               /* Now get the lock to safely insert the records.  */
145               pthread_rwlock_rdlock (&db->lock);
146
147               if (cache_add (req->type, &dataset->strdata, req->key_len,
148                              &dataset->head, true, db, owner) < 0)
149                 /* Ensure the data can be recovered.  */
150                 dataset->head.usable = false;
151
152               pthread_rwlock_unlock (&db->lock);
153
154               /* Mark the old entry as obsolete.  */
155               if (dh != NULL)
156                 dh->usable = false;
157             }
158           else
159             ++db->head->addfailed;
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 = (sizeof (struct dataset)
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         {
206           dataset = (struct dataset *) mempool_alloc (db, total + n);
207           if (dataset == NULL)
208             ++db->head->addfailed;
209         }
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       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       /* Now we can determine whether on refill we have to create a new
255          record or not.  */
256       if (he != NULL)
257         {
258           assert (fd == -1);
259
260           if (total + n == dh->allocsize
261               && total - offsetof (struct dataset, resp) == dh->recsize
262               && memcmp (&dataset->resp, dh->data,
263                          dh->allocsize - offsetof (struct dataset, resp)) == 0)
264             {
265               /* The data has not changed.  We will just bump the
266                  timeout value.  Note that the new record has been
267                  allocated on the stack and need not be freed.  */
268               dh->timeout = dataset->head.timeout;
269               ++dh->nreloads;
270             }
271           else
272             {
273               /* We have to create a new record.  Just allocate
274                  appropriate memory and copy it.  */
275               struct dataset *newp
276                 = (struct dataset *) mempool_alloc (db, total + n);
277               if (newp != NULL)
278                 {
279                   /* Adjust pointers into the memory block.  */
280                   gr_name = (char *) newp + (gr_name - (char *) dataset);
281                   cp = (char *) newp + (cp - (char *) dataset);
282                   key_copy = (char *) newp + (key_copy - (char *) dataset);
283
284                   dataset = memcpy (newp, dataset, total + n);
285                   alloca_used = false;
286                 }
287
288               /* Mark the old record as obsolete.  */
289               dh->usable = false;
290             }
291         }
292       else
293         {
294           /* We write the dataset before inserting it to the database
295              since while inserting this thread might block and so would
296              unnecessarily let the receiver wait.  */
297           assert (fd != -1);
298
299 #ifdef HAVE_SENDFILE
300           if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
301             {
302               assert (db->wr_fd != -1);
303               assert ((char *) &dataset->resp > (char *) db->data);
304               assert ((char *) &dataset->resp - (char *) db->head
305                       + total
306                       <= (sizeof (struct database_pers_head)
307                           + db->head->module * sizeof (ref_t)
308                           + db->head->data_size));
309               written = sendfileall (fd, db->wr_fd,
310                                      (char *) &dataset->resp
311                                      - (char *) db->head, total);
312 # ifndef __ASSUME_SENDFILE
313               if (written == -1 && errno == ENOSYS)
314                 goto use_write;
315 # endif
316             }
317           else
318 # ifndef __ASSUME_SENDFILE
319           use_write:
320 # endif
321 #endif
322             written = writeall (fd, &dataset->resp, total);
323         }
324
325       /* Add the record to the database.  But only if it has not been
326          stored on the stack.  */
327       if (! alloca_used)
328         {
329           /* If necessary, we also propagate the data to disk.  */
330           if (db->persistent)
331             {
332               // XXX async OK?
333               uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
334               msync ((void *) pval,
335                      ((uintptr_t) dataset & pagesize_m1) + total + n,
336                      MS_ASYNC);
337             }
338
339           /* Now get the lock to safely insert the records.  */
340           pthread_rwlock_rdlock (&db->lock);
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) < 0)
353                 {
354                   /* Could not allocate memory.  Make sure the data gets
355                      discarded.  */
356                   dataset->head.usable = false;
357                   goto out;
358                 }
359
360               first = false;
361             }
362           /* If the key is different from the name add a separate entry.  */
363           else if (strcmp (key_copy, gr_name) != 0)
364             {
365               if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
366                              &dataset->head, true, db, owner) < 0)
367                 {
368                   /* Could not allocate memory.  Make sure the data gets
369                      discarded.  */
370                   dataset->head.usable = false;
371                   goto out;
372                 }
373
374               first = false;
375             }
376
377           /* We have to add the value for both, byname and byuid.  */
378           if ((req->type == GETGRBYNAME || db->propagate)
379               && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
380                                               gr_name_len,
381                                               &dataset->head, first, db, owner)
382                                    == 0, 1))
383             {
384               if (req->type == GETGRBYNAME && db->propagate)
385                 (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
386                                   req->type != GETGRBYNAME, db, owner);
387             }
388           else if (first)
389             /* Could not allocate memory.  Make sure the data gets
390                discarded.  */
391             dataset->head.usable = false;
392
393         out:
394           pthread_rwlock_unlock (&db->lock);
395         }
396     }
397
398   if (__builtin_expect (written != total, 0) && debug_level > 0)
399     {
400       char buf[256];
401       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
402                strerror_r (errno, buf, sizeof (buf)));
403     }
404 }
405
406
407 union keytype
408 {
409   void *v;
410   gid_t g;
411 };
412
413
414 static int
415 lookup (int type, union keytype key, struct group *resultbufp, char *buffer,
416         size_t buflen, struct group **grp)
417 {
418   if (type == GETGRBYNAME)
419     return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp);
420   else
421     return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp);
422 }
423
424
425 static void
426 addgrbyX (struct database_dyn *db, int fd, request_header *req,
427           union keytype key, const char *keystr, uid_t uid,
428           struct hashentry *he, struct datahead *dh)
429 {
430   /* Search for the entry matching the key.  Please note that we don't
431      look again in the table whether the dataset is now available.  We
432      simply insert it.  It does not matter if it is in there twice.  The
433      pruning function only will look at the timestamp.  */
434   size_t buflen = 1024;
435   char *buffer = (char *) alloca (buflen);
436   struct group resultbuf;
437   struct group *grp;
438   bool use_malloc = false;
439   int errval = 0;
440
441   if (__builtin_expect (debug_level > 0, 0))
442     {
443       if (he == NULL)
444         dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
445       else
446         dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
447     }
448
449 #if 0
450   uid_t oldeuid = 0;
451   if (db->secure)
452     {
453       oldeuid = geteuid ();
454       pthread_seteuid_np (uid);
455     }
456 #endif
457
458   while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
459          && (errval = errno) == ERANGE)
460     {
461       char *old_buffer = buffer;
462       errno = 0;
463
464       if (__builtin_expect (buflen > 32768, 0))
465         {
466           buflen *= 2;
467           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
468           if (buffer == NULL)
469             {
470               /* We ran out of memory.  We cannot do anything but
471                  sending a negative response.  In reality this should
472                  never happen.  */
473               grp = NULL;
474               buffer = old_buffer;
475
476               /* We set the error to indicate this is (possibly) a
477                  temporary error and that it does not mean the entry
478                  is not available at all.  */
479               errval = EAGAIN;
480               break;
481             }
482           use_malloc = true;
483         }
484       else
485         /* Allocate a new buffer on the stack.  If possible combine it
486            with the previously allocated buffer.  */
487         buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
488     }
489
490 #if 0
491   if (db->secure)
492     pthread_seteuid_np (oldeuid);
493 #endif
494
495   cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
496
497   if (use_malloc)
498     free (buffer);
499 }
500
501
502 void
503 addgrbyname (struct database_dyn *db, int fd, request_header *req,
504              void *key, uid_t uid)
505 {
506   union keytype u = { .v = key };
507
508   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
509 }
510
511
512 void
513 readdgrbyname (struct database_dyn *db, struct hashentry *he,
514                struct datahead *dh)
515 {
516   request_header req =
517     {
518       .type = GETGRBYNAME,
519       .key_len = he->len
520     };
521   union keytype u = { .v = db->data + he->key };
522
523   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
524 }
525
526
527 void
528 addgrbygid (struct database_dyn *db, int fd, request_header *req,
529             void *key, uid_t uid)
530 {
531   char *ep;
532   gid_t gid = strtoul ((char *) key, &ep, 10);
533
534   if (*(char *) key == '\0' || *ep != '\0')  /* invalid numeric uid */
535     {
536       if (debug_level > 0)
537         dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
538
539       errno = EINVAL;
540       return;
541     }
542
543   union keytype u = { .g = gid };
544
545   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
546 }
547
548
549 void
550 readdgrbygid (struct database_dyn *db, struct hashentry *he,
551               struct datahead *dh)
552 {
553   char *ep;
554   gid_t gid = strtoul (db->data + he->key, &ep, 10);
555
556   /* Since the key has been added before it must be OK.  */
557   assert (*(db->data + he->key) != '\0' && *ep == '\0');
558
559   request_header req =
560     {
561       .type = GETGRBYGID,
562       .key_len = he->len
563     };
564   union keytype u = { .g = gid };
565
566   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
567 }