summaryrefslogtreecommitdiff
path: root/nscd/netgroupcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'nscd/netgroupcache.c')
-rw-r--r--nscd/netgroupcache.c153
1 files changed, 89 insertions, 64 deletions
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index a607dda0a5..be01fe8670 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -1,5 +1,5 @@
/* Cache handling for netgroup lookup.
- Copyright (C) 2011-2013 Free Software Foundation, Inc.
+ Copyright (C) 2011-2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
@@ -65,6 +65,55 @@ struct dataset
char strdata[0];
};
+/* Sends a notfound message and prepares a notfound dataset to write to the
+ cache. Returns true if there was enough memory to allocate the dataset and
+ returns the dataset in DATASETP, total bytes to write in TOTALP and the
+ timeout in TIMEOUTP. KEY_COPY is set to point to the copy of the key in the
+ dataset. */
+static bool
+do_notfound (struct database_dyn *db, int fd, request_header *req,
+ const char *key, struct dataset **datasetp, ssize_t *totalp,
+ time_t *timeoutp, char **key_copy)
+{
+ struct dataset *dataset;
+ ssize_t total;
+ time_t timeout;
+ bool cacheable = false;
+
+ total = sizeof (notfound);
+ timeout = time (NULL) + db->negtimeout;
+
+ if (fd != -1)
+ TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
+ /* If we cannot permanently store the result, so be it. */
+ if (dataset != NULL)
+ {
+ dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+ dataset->head.recsize = total;
+ dataset->head.notfound = true;
+ dataset->head.nreloads = 0;
+ dataset->head.usable = true;
+
+ /* Compute the timeout time. */
+ timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
+ dataset->head.ttl = db->negtimeout;
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, &notfound, total);
+
+ /* Copy the key data. */
+ memcpy (dataset->strdata, key, req->key_len);
+ *key_copy = dataset->strdata;
+
+ cacheable = true;
+ }
+ *timeoutp = timeout;
+ *totalp = total;
+ *datasetp = dataset;
+ return cacheable;
+}
static time_t
addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
@@ -84,6 +133,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
struct dataset *dataset;
bool cacheable = false;
ssize_t total;
+ bool found = false;
char *key_copy = NULL;
struct __netgrent data;
@@ -91,7 +141,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
size_t buffilled = sizeof (*dataset);
char *buffer = NULL;
size_t nentries = 0;
- bool use_malloc = false;
size_t group_len = strlen (key) + 1;
union
{
@@ -103,40 +152,13 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
&& __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
{
/* No such service. */
- total = sizeof (notfound);
- timeout = time (NULL) + db->negtimeout;
-
- if (fd != -1)
- TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
-
- dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
- /* If we cannot permanently store the result, so be it. */
- if (dataset != NULL)
- {
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
- dataset->head.ttl = db->negtimeout;
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- memcpy (dataset->strdata, key, req->key_len);
-
- cacheable = true;
- }
-
+ cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
+ &key_copy);
goto writeout;
}
memset (&data, '\0', sizeof (data));
- buffer = alloca (buflen);
+ buffer = xmalloc (buflen);
first_needed.elem.next = &first_needed.elem;
memcpy (first_needed.elem.name, key, group_len);
data.needed_groups = &first_needed.elem;
@@ -167,6 +189,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
if (status == NSS_STATUS_SUCCESS)
{
+ found = true;
union
{
enum nss_status (*f) (struct __netgrent *, char *, size_t,
@@ -180,9 +203,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
int e;
status = getfct.f (&data, buffer + buffilled,
buflen - buffilled, &e);
- if (status == NSS_STATUS_RETURN)
- /* This was the last one for this group. Look
- at next group if available. */
+ if (status == NSS_STATUS_RETURN
+ || status == NSS_STATUS_NOTFOUND)
+ /* This was either the last one for this group or the
+ group was empty. Look at next group if available. */
break;
if (status == NSS_STATUS_SUCCESS)
{
@@ -216,21 +240,24 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
if (buflen - req->key_len - bufused < needed)
{
- size_t newsize = MAX (2 * buflen,
- buflen + 2 * needed);
- if (use_malloc || newsize > 1024 * 1024)
- {
- buflen = newsize;
- char *newbuf = xrealloc (use_malloc
- ? buffer
- : NULL,
- buflen);
-
- buffer = newbuf;
- use_malloc = true;
- }
- else
- extend_alloca (buffer, buflen, newsize);
+ buflen += MAX (buflen, 2 * needed);
+ /* Save offset in the old buffer. We don't
+ bother with the NULL check here since
+ we'll do that later anyway. */
+ size_t nhostdiff = nhost - buffer;
+ size_t nuserdiff = nuser - buffer;
+ size_t ndomaindiff = ndomain - buffer;
+
+ char *newbuf = xrealloc (buffer, buflen);
+ /* Fix up the triplet pointers into the new
+ buffer. */
+ nhost = (nhost ? newbuf + nhostdiff
+ : NULL);
+ nuser = (nuser ? newbuf + nuserdiff
+ : NULL);
+ ndomain = (ndomain ? newbuf + ndomaindiff
+ : NULL);
+ buffer = newbuf;
}
nhost = memcpy (buffer + bufused,
@@ -297,18 +324,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
{
- size_t newsize = 2 * buflen;
- if (use_malloc || newsize > 1024 * 1024)
- {
- buflen = newsize;
- char *newbuf = xrealloc (use_malloc
- ? buffer : NULL, buflen);
-
- buffer = newbuf;
- use_malloc = true;
- }
- else
- extend_alloca (buffer, buflen, newsize);
+ buflen *= 2;
+ buffer = xrealloc (buffer, buflen);
}
}
@@ -325,6 +342,15 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
}
+ /* No results. Return a failure and write out a notfound record in the
+ cache. */
+ if (!found)
+ {
+ cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
+ &key_copy);
+ goto writeout;
+ }
+
total = buffilled;
/* Fill in the dataset. */
@@ -444,8 +470,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
out:
- if (use_malloc)
- free (buffer);
+ free (buffer);
*resultp = dataset;