Fix parameter name.
[glibc/pb-stable.git] / nscd / grpcache.c
blob11a2e717080b64d0647cb77aea58be86967ff4dc
1 /* Cache handling for group lookup.
2 Copyright (C) 1998-2002, 2003 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
19 02111-1307 USA. */
21 #include <alloca.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <grp.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 <libintl.h>
33 #include <stackinfo.h>
35 #include "nscd.h"
36 #include "dbg_log.h"
38 /* This is the standard reply in case the service is disabled. */
39 static const gr_response_header disabled =
41 .version = NSCD_VERSION,
42 .found = -1,
43 .gr_name_len = 0,
44 .gr_passwd_len = 0,
45 .gr_gid = -1,
46 .gr_mem_cnt = 0,
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,
61 .found = 0,
62 .gr_name_len = 0,
63 .gr_passwd_len = 0,
64 .gr_gid = -1,
65 .gr_mem_cnt = 0,
68 /* This is the struct describing how to write this record. */
69 static const struct iovec iov_notfound =
71 .iov_base = (void *) &notfound,
72 .iov_len = sizeof (notfound)
76 struct groupdata
78 gr_response_header resp;
79 char strdata[0];
83 static void
84 cache_addgr (struct database *db, int fd, request_header *req, void *key,
85 struct group *grp, uid_t owner)
87 ssize_t total;
88 ssize_t written;
89 time_t t = time (NULL);
91 if (grp == NULL)
93 /* We have no data. This means we send the standard reply for this
94 case. */
95 void *copy;
97 total = sizeof (notfound);
99 written = TEMP_FAILURE_RETRY (writev (fd, &iov_notfound, 1));
101 copy = malloc (req->key_len);
102 if (copy == NULL)
103 error (EXIT_FAILURE, errno, _("while allocating key copy"));
104 memcpy (copy, key, req->key_len);
106 /* Compute the timeout time. */
107 t += db->negtimeout;
109 /* Now get the lock to safely insert the records. */
110 pthread_rwlock_rdlock (&db->lock);
112 cache_add (req->type, copy, req->key_len, &notfound,
113 sizeof (notfound), (void *) -1, 0, t, db, owner);
115 pthread_rwlock_unlock (&db->lock);
117 else
119 /* Determine the I/O structure. */
120 struct groupdata *data;
121 size_t gr_name_len = strlen (grp->gr_name) + 1;
122 size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
123 size_t gr_mem_cnt = 0;
124 uint32_t *gr_mem_len;
125 size_t gr_mem_len_total = 0;
126 char *gr_name;
127 char *cp;
128 char buf[12];
129 ssize_t n;
130 size_t cnt;
132 /* We need this to insert the `bygid' entry. */
133 n = snprintf (buf, sizeof (buf), "%d", grp->gr_gid) + 1;
135 /* Determine the length of all members. */
136 while (grp->gr_mem[gr_mem_cnt])
137 ++gr_mem_cnt;
138 gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
139 for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
141 gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
142 gr_mem_len_total += gr_mem_len[gr_mem_cnt];
145 /* We allocate all data in one memory block: the iov vector,
146 the response header and the dataset itself. */
147 total = (sizeof (struct groupdata)
148 + gr_mem_cnt * sizeof (uint32_t)
149 + gr_name_len + gr_passwd_len + gr_mem_len_total);
150 data = (struct groupdata *) malloc (total + n);
151 if (data == NULL)
152 /* There is no reason to go on. */
153 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
155 data->resp.version = NSCD_VERSION;
156 data->resp.found = 1;
157 data->resp.gr_name_len = gr_name_len;
158 data->resp.gr_passwd_len = gr_passwd_len;
159 data->resp.gr_gid = grp->gr_gid;
160 data->resp.gr_mem_cnt = gr_mem_cnt;
162 cp = data->strdata;
164 /* This is the member string length array. */
165 cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
166 gr_name = cp;
167 cp = mempcpy (cp, grp->gr_name, gr_name_len);
168 cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
170 for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
171 cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
173 /* Finally the stringified GID value. */
174 memcpy (cp, buf, n);
176 /* Write the result. */
177 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
179 /* Compute the timeout time. */
180 t += db->postimeout;
182 /* Now get the lock to safely insert the records. */
183 pthread_rwlock_rdlock (&db->lock);
185 /* We have to add the value for both, byname and byuid. */
186 cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
187 total, data, 0, t, db, owner);
189 cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
191 pthread_rwlock_unlock (&db->lock);
194 if (__builtin_expect (written != total, 0) && debug_level > 0)
196 char buf[256];
197 dbg_log (_("short write in %s: %s"), __FUNCTION__,
198 strerror_r (errno, buf, sizeof (buf)));
203 void
204 addgrbyname (struct database *db, int fd, request_header *req,
205 void *key, uid_t uid)
207 /* Search for the entry matching the key. Please note that we don't
208 look again in the table whether the dataset is now available. We
209 simply insert it. It does not matter if it is in there twice. The
210 pruning function only will look at the timestamp. */
211 int buflen = 1024;
212 char *buffer = (char *) alloca (buflen);
213 struct group resultbuf;
214 struct group *grp;
215 uid_t oldeuid = 0;
216 bool use_malloc = false;
218 if (__builtin_expect (debug_level > 0, 0))
219 dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
221 if (secure[grpdb])
223 oldeuid = geteuid ();
224 seteuid (uid);
227 while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
228 && errno == ERANGE)
230 char *old_buffer = buffer;
231 errno = 0;
232 #define INCR 1024
234 if (__builtin_expect (buflen > 32768, 0))
236 buflen += INCR;
237 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
238 if (buffer == NULL)
240 /* We ran out of memory. We cannot do anything but
241 sending a negative response. In reality this should
242 never happen. */
243 grp = NULL;
244 buffer = old_buffer;
245 break;
247 use_malloc = true;
249 else
250 /* Allocate a new buffer on the stack. If possible combine it
251 with the previously allocated buffer. */
252 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
255 if (secure[grpdb])
256 seteuid (oldeuid);
258 cache_addgr (db, fd, req, key, grp, uid);
260 if (use_malloc)
261 free (buffer);
265 void
266 addgrbygid (struct database *db, int fd, request_header *req,
267 void *key, uid_t uid)
269 /* Search for the entry matching the key. Please note that we don't
270 look again in the table whether the dataset is now available. We
271 simply insert it. It does not matter if it is in there twice. The
272 pruning function only will look at the timestamp. */
273 int buflen = 1024;
274 char *buffer = (char *) alloca (buflen);
275 struct group resultbuf;
276 struct group *grp;
277 uid_t oldeuid = 0;
278 char *ep;
279 gid_t gid = strtoul ((char *)key, &ep, 10);
280 bool use_malloc = false;
282 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric gid */
284 if (debug_level > 0)
285 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
287 errno = EINVAL;
288 return;
291 if (__builtin_expect (debug_level > 0, 0))
292 dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
294 if (secure[grpdb])
296 oldeuid = geteuid ();
297 seteuid (uid);
300 while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
301 && errno == ERANGE)
303 char *old_buffer = buffer;
304 errno = 0;
306 if (__builtin_expect (buflen > 32768, 0))
308 buflen += INCR;
309 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
310 if (buffer == NULL)
312 /* We ran out of memory. We cannot do anything but
313 sending a negative response. In reality this should
314 never happen. */
315 grp = NULL;
316 buffer = old_buffer;
317 break;
319 use_malloc = true;
321 else
322 /* Allocate a new buffer on the stack. If possible combine it
323 with the previously allocated buffer. */
324 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
327 if (secure[grpdb])
328 seteuid (oldeuid);
330 cache_addgr (db, fd, req, key, grp, uid);
332 if (use_malloc)
333 free (buffer);