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