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