1 /* Cache handling for group lookup.
2 Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
33 #include <stackinfo.h>
38 /* This is the standard reply in case the service is disabled. */
39 static const gr_response_header disabled =
41 .version = NSCD_VERSION,
49 /* This is the struct describing how to write this record. */
50 const struct iovec grp_iov_disabled =
52 .iov_base = (void *) &disabled,
53 .iov_len = sizeof (disabled)
57 /* This is the standard reply in case we haven't found the dataset. */
58 static const gr_response_header notfound =
60 .version = NSCD_VERSION,
71 gr_response_header resp;
77 cache_addgr (struct database *db, int fd, request_header *req, void *key,
78 struct group *grp, uid_t owner, int type)
82 time_t t = time (NULL);
86 /* We have no data. This means we send the standard reply for this
88 total = sizeof (notfound);
90 written = TEMP_FAILURE_RETRY (write (fd, ¬found, total));
92 void *copy = malloc (req->key_len);
93 /* If we cannot allocate memory simply do not cache the information. */
96 memcpy (copy, key, req->key_len);
98 /* Compute the timeout time. */
101 /* Now get the lock to safely insert the records. */
102 pthread_rwlock_rdlock (&db->lock);
104 cache_add (req->type, copy, req->key_len, ¬found,
105 sizeof (notfound), (void *) -1, 0, t, db, owner);
107 pthread_rwlock_unlock (&db->lock);
112 /* Determine the I/O structure. */
113 struct groupdata *data;
114 size_t gr_name_len = strlen (grp->gr_name) + 1;
115 size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
116 size_t gr_mem_cnt = 0;
117 uint32_t *gr_mem_len;
118 size_t gr_mem_len_total = 0;
125 /* We need this to insert the `bygid' entry. */
126 n = snprintf (buf, sizeof (buf), "%d", grp->gr_gid) + 1;
128 /* Determine the length of all members. */
129 while (grp->gr_mem[gr_mem_cnt])
131 gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
132 for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
134 gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
135 gr_mem_len_total += gr_mem_len[gr_mem_cnt];
138 /* We allocate all data in one memory block: the iov vector,
139 the response header and the dataset itself. */
140 total = (sizeof (struct groupdata)
141 + gr_mem_cnt * sizeof (uint32_t)
142 + gr_name_len + gr_passwd_len + gr_mem_len_total);
143 data = (struct groupdata *) malloc (total + n + req->key_len);
145 /* There is no reason to go on. */
146 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
148 data->resp.version = NSCD_VERSION;
149 data->resp.found = 1;
150 data->resp.gr_name_len = gr_name_len;
151 data->resp.gr_passwd_len = gr_passwd_len;
152 data->resp.gr_gid = grp->gr_gid;
153 data->resp.gr_mem_cnt = gr_mem_cnt;
157 /* This is the member string length array. */
158 cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
160 cp = mempcpy (cp, grp->gr_name, gr_name_len);
161 cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
163 for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
164 cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
166 /* Next the stringified GID value. */
169 /* Copy of the key in case it differs. */
170 char *key_copy = memcpy (cp + n, key, req->key_len);
172 /* Write the result. */
173 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
175 /* Compute the timeout time. */
178 /* Now get the lock to safely insert the records. */
179 pthread_rwlock_rdlock (&db->lock);
181 /* We have to add the value for both, byname and byuid. */
182 cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
183 total, data, 0, t, db, owner);
185 /* If the key is different from the name add a separate entry. */
186 if (type == GETGRBYNAME && strcmp (key_copy, gr_name) != 0)
187 cache_add (GETGRBYNAME, key_copy, req->key_len, data,
188 total, data, 0, t, db, owner);
190 cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
192 pthread_rwlock_unlock (&db->lock);
195 if (__builtin_expect (written != total, 0) && debug_level > 0)
198 dbg_log (_("short write in %s: %s"), __FUNCTION__,
199 strerror_r (errno, buf, sizeof (buf)));
205 addgrbyname (struct database *db, int fd, request_header *req,
206 void *key, uid_t uid)
208 /* Search for the entry matching the key. Please note that we don't
209 look again in the table whether the dataset is now available. We
210 simply insert it. It does not matter if it is in there twice. The
211 pruning function only will look at the timestamp. */
213 char *buffer = (char *) alloca (buflen);
214 struct group resultbuf;
217 bool use_malloc = false;
219 if (__builtin_expect (debug_level > 0, 0))
220 dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
224 oldeuid = geteuid ();
228 while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
231 char *old_buffer = buffer;
235 if (__builtin_expect (buflen > 32768, 0))
238 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
241 /* We ran out of memory. We cannot do anything but
242 sending a negative response. In reality this should
251 /* Allocate a new buffer on the stack. If possible combine it
252 with the previously allocated buffer. */
253 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
259 cache_addgr (db, fd, req, key, grp, uid, GETGRBYNAME);
267 addgrbygid (struct database *db, int fd, request_header *req,
268 void *key, uid_t uid)
270 /* Search for the entry matching the key. Please note that we don't
271 look again in the table whether the dataset is now available. We
272 simply insert it. It does not matter if it is in there twice. The
273 pruning function only will look at the timestamp. */
275 char *buffer = (char *) alloca (buflen);
276 struct group resultbuf;
280 gid_t gid = strtoul ((char *)key, &ep, 10);
281 bool use_malloc = false;
283 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric gid */
286 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
292 if (__builtin_expect (debug_level > 0, 0))
293 dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
297 oldeuid = geteuid ();
301 while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
304 char *old_buffer = buffer;
307 if (__builtin_expect (buflen > 32768, 0))
310 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
313 /* We ran out of memory. We cannot do anything but
314 sending a negative response. In reality this should
323 /* Allocate a new buffer on the stack. If possible combine it
324 with the previously allocated buffer. */
325 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
331 cache_addgr (db, fd, req, key, grp, uid, GETGRBYGID);