* nscd/nscd.h (struct database_dyn): Add propagate field.
[platform/upstream/glibc.git] / nscd / grpcache.c
1 /* Cache handling for group lookup.
2    Copyright (C) 1998-2005, 2006 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
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->resp - (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, total);
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, total);
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           /* Now get the lock to safely insert the records.  */
339           pthread_rwlock_rdlock (&db->lock);
340
341           /* NB: in the following code we always must add the entry
342              marked with FIRST first.  Otherwise we end up with
343              dangling "pointers" in case a latter hash entry cannot be
344              added.  */
345           bool first = true;
346
347           /* If the request was by GID, add that entry first.  */
348           if (req->type == GETGRBYGID)
349             {
350               if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
351                              db, owner) < 0)
352                 {
353                   /* Could not allocate memory.  Make sure the data gets
354                      discarded.  */
355                   dataset->head.usable = false;
356                   goto out;
357                 }
358
359               first = false;
360             }
361           /* If the key is different from the name add a separate entry.  */
362           else if (strcmp (key_copy, gr_name) != 0)
363             {
364               if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
365                              &dataset->head, true, db, owner) < 0)
366                 {
367                   /* Could not allocate memory.  Make sure the data gets
368                      discarded.  */
369                   dataset->head.usable = false;
370                   goto out;
371                 }
372
373               first = false;
374             }
375
376           /* We have to add the value for both, byname and byuid.  */
377           if ((req->type == GETGRBYNAME || db->propagate)
378               && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
379                                               gr_name_len,
380                                               &dataset->head, first, db, owner)
381                                    == 0, 1))
382             {
383               if (req->type == GETGRBYNAME && db->propagate)
384                 (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
385                                   req->type != GETGRBYNAME, db, owner);
386             }
387           else if (first)
388             /* Could not allocate memory.  Make sure the data gets
389                discarded.  */
390             dataset->head.usable = false;
391
392         out:
393           pthread_rwlock_unlock (&db->lock);
394         }
395     }
396
397   if (__builtin_expect (written != total, 0) && debug_level > 0)
398     {
399       char buf[256];
400       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
401                strerror_r (errno, buf, sizeof (buf)));
402     }
403 }
404
405
406 union keytype
407 {
408   void *v;
409   gid_t g;
410 };
411
412
413 static int
414 lookup (int type, union keytype key, struct group *resultbufp, char *buffer,
415         size_t buflen, struct group **grp)
416 {
417   if (type == GETGRBYNAME)
418     return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp);
419   else
420     return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp);
421 }
422
423
424 static void
425 addgrbyX (struct database_dyn *db, int fd, request_header *req,
426           union keytype key, const char *keystr, uid_t uid,
427           struct hashentry *he, struct datahead *dh)
428 {
429   /* Search for the entry matching the key.  Please note that we don't
430      look again in the table whether the dataset is now available.  We
431      simply insert it.  It does not matter if it is in there twice.  The
432      pruning function only will look at the timestamp.  */
433   size_t buflen = 1024;
434   char *buffer = (char *) alloca (buflen);
435   struct group resultbuf;
436   struct group *grp;
437   bool use_malloc = false;
438   int errval = 0;
439
440   if (__builtin_expect (debug_level > 0, 0))
441     {
442       if (he == NULL)
443         dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
444       else
445         dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
446     }
447
448 #if 0
449   uid_t oldeuid = 0;
450   if (db->secure)
451     {
452       oldeuid = geteuid ();
453       pthread_seteuid_np (uid);
454     }
455 #endif
456
457   while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
458          && (errval = errno) == ERANGE)
459     {
460       char *old_buffer = buffer;
461       errno = 0;
462
463       if (__builtin_expect (buflen > 32768, 0))
464         {
465           buflen *= 2;
466           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
467           if (buffer == NULL)
468             {
469               /* We ran out of memory.  We cannot do anything but
470                  sending a negative response.  In reality this should
471                  never happen.  */
472               grp = NULL;
473               buffer = old_buffer;
474
475               /* We set the error to indicate this is (possibly) a
476                  temporary error and that it does not mean the entry
477                  is not available at all.  */
478               errval = EAGAIN;
479               break;
480             }
481           use_malloc = true;
482         }
483       else
484         /* Allocate a new buffer on the stack.  If possible combine it
485            with the previously allocated buffer.  */
486         buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
487     }
488
489 #if 0
490   if (db->secure)
491     pthread_seteuid_np (oldeuid);
492 #endif
493
494   cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
495
496   if (use_malloc)
497     free (buffer);
498 }
499
500
501 void
502 addgrbyname (struct database_dyn *db, int fd, request_header *req,
503              void *key, uid_t uid)
504 {
505   union keytype u = { .v = key };
506
507   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
508 }
509
510
511 void
512 readdgrbyname (struct database_dyn *db, struct hashentry *he,
513                struct datahead *dh)
514 {
515   request_header req =
516     {
517       .type = GETGRBYNAME,
518       .key_len = he->len
519     };
520   union keytype u = { .v = db->data + he->key };
521
522   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
523 }
524
525
526 void
527 addgrbygid (struct database_dyn *db, int fd, request_header *req,
528             void *key, uid_t uid)
529 {
530   char *ep;
531   gid_t gid = strtoul ((char *) key, &ep, 10);
532
533   if (*(char *) key == '\0' || *ep != '\0')  /* invalid numeric uid */
534     {
535       if (debug_level > 0)
536         dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
537
538       errno = EINVAL;
539       return;
540     }
541
542   union keytype u = { .g = gid };
543
544   addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
545 }
546
547
548 void
549 readdgrbygid (struct database_dyn *db, struct hashentry *he,
550               struct datahead *dh)
551 {
552   char *ep;
553   gid_t gid = strtoul (db->data + he->key, &ep, 10);
554
555   /* Since the key has been added before it must be OK.  */
556   assert (*(db->data + he->key) != '\0' && *ep == '\0');
557
558   request_header req =
559     {
560       .type = GETGRBYGID,
561       .key_len = he->len
562     };
563   union keytype u = { .g = gid };
564
565   addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
566 }