]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/grpcache.c
Update.
[thirdparty/glibc.git] / nscd / grpcache.c
CommitLineData
67479a70 1/* Cache handling for group lookup.
9caf4f1c 2 Copyright (C) 1998-2002, 2003 Free Software Foundation, Inc.
d67281a7 3 This file is part of the GNU C Library.
67479a70 4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
d67281a7
UD
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
d67281a7
UD
10
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
41bdb6e2 14 Lesser General Public License for more details.
d67281a7 15
41bdb6e2
AJ
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. */
d67281a7 20
9caf4f1c 21#include <alloca.h>
d67281a7 22#include <errno.h>
67479a70 23#include <error.h>
d67281a7 24#include <grp.h>
0472723a 25#include <stdbool.h>
67479a70
UD
26#include <stddef.h>
27#include <stdio.h>
3107c0c5 28#include <stdint.h>
da2d1bc5 29#include <stdlib.h>
d67281a7 30#include <string.h>
ba9234d9 31#include <unistd.h>
4360eafd 32#include <libintl.h>
0472723a 33#include <stackinfo.h>
d67281a7 34
d67281a7 35#include "nscd.h"
67479a70 36#include "dbg_log.h"
d67281a7 37
67479a70
UD
38/* This is the standard reply in case the service is disabled. */
39static const gr_response_header disabled =
d67281a7 40{
c2e13112
RM
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,
d67281a7 47};
d67281a7 48
67479a70
UD
49/* This is the struct describing how to write this record. */
50const struct iovec grp_iov_disabled =
d67281a7 51{
c2e13112
RM
52 .iov_base = (void *) &disabled,
53 .iov_len = sizeof (disabled)
d67281a7 54};
d67281a7 55
67479a70
UD
56
57/* This is the standard reply in case we haven't found the dataset. */
58static const gr_response_header notfound =
d67281a7 59{
c2e13112
RM
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,
d67281a7 66};
d67281a7 67
67479a70
UD
68/* This is the struct describing how to write this record. */
69static const struct iovec iov_notfound =
d67281a7 70{
c2e13112
RM
71 .iov_base = (void *) &notfound,
72 .iov_len = sizeof (notfound)
67479a70 73};
d67281a7 74
d67281a7 75
67479a70 76struct groupdata
d67281a7 77{
67479a70
UD
78 gr_response_header resp;
79 char strdata[0];
80};
d67281a7 81
d67281a7 82
67479a70
UD
83static void
84cache_addgr (struct database *db, int fd, request_header *req, void *key,
a1c542bf 85 struct group *grp, uid_t owner)
d67281a7 86{
67479a70
UD
87 ssize_t total;
88 ssize_t written;
89 time_t t = time (NULL);
d67281a7 90
67479a70 91 if (grp == NULL)
d67281a7 92 {
67479a70
UD
93 /* We have no data. This means we send the standard reply for this
94 case. */
95 void *copy;
d67281a7 96
67479a70 97 total = sizeof (notfound);
d67281a7 98
9caf4f1c 99 written = TEMP_FAILURE_RETRY (writev (fd, &iov_notfound, 1));
d67281a7 100
67479a70
UD
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);
d67281a7 105
67479a70
UD
106 /* Compute the timeout time. */
107 t += db->negtimeout;
14e9dd67 108
67479a70
UD
109 /* Now get the lock to safely insert the records. */
110 pthread_rwlock_rdlock (&db->lock);
d67281a7 111
d0db5f48 112 cache_add (req->type, copy, req->key_len, &notfound,
a1c542bf 113 sizeof (notfound), (void *) -1, 0, t, db, owner);
d67281a7 114
67479a70 115 pthread_rwlock_unlock (&db->lock);
d67281a7 116 }
ba9234d9
UD
117 else
118 {
67479a70
UD
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;
3107c0c5 124 uint32_t *gr_mem_len;
67479a70
UD
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;
131
132 /* We need this to insert the `bygid' entry. */
133 n = snprintf (buf, sizeof (buf), "%d", grp->gr_gid) + 1;
134
135 /* Determine the length of all members. */
136 while (grp->gr_mem[gr_mem_cnt])
137 ++gr_mem_cnt;
3107c0c5 138 gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
67479a70
UD
139 for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
140 {
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];
143 }
ba9234d9 144
67479a70
UD
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)
3107c0c5 148 + gr_mem_cnt * sizeof (uint32_t)
67479a70
UD
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"));
d67281a7 154
fe453812 155 data->resp.version = NSCD_VERSION;
67479a70
UD
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;
d67281a7 161
67479a70 162 cp = data->strdata;
d67281a7 163
67479a70 164 /* This is the member string length array. */
3107c0c5 165 cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
0a55a284
UD
166 gr_name = cp;
167 cp = mempcpy (cp, grp->gr_name, gr_name_len);
67479a70 168 cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
d67281a7 169
67479a70
UD
170 for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
171 cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
d67281a7 172
67479a70
UD
173 /* Finally the stringified GID value. */
174 memcpy (cp, buf, n);
d67281a7 175
67479a70 176 /* Write the result. */
23700036 177 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
d67281a7 178
67479a70
UD
179 /* Compute the timeout time. */
180 t += db->postimeout;
d67281a7 181
67479a70
UD
182 /* Now get the lock to safely insert the records. */
183 pthread_rwlock_rdlock (&db->lock);
14e9dd67 184
67479a70
UD
185 /* We have to add the value for both, byname and byuid. */
186 cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
a1c542bf 187 total, data, 0, t, db, owner);
d67281a7 188
a1c542bf 189 cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
d67281a7 190
67479a70 191 pthread_rwlock_unlock (&db->lock);
d67281a7
UD
192 }
193
23700036 194 if (__builtin_expect (written != total, 0) && debug_level > 0)
d67281a7 195 {
67479a70
UD
196 char buf[256];
197 dbg_log (_("short write in %s: %s"), __FUNCTION__,
198 strerror_r (errno, buf, sizeof (buf)));
d67281a7 199 }
d67281a7
UD
200}
201
d67281a7 202
67479a70 203void
a1c542bf
UD
204addgrbyname (struct database *db, int fd, request_header *req,
205 void *key, uid_t uid)
67479a70
UD
206{
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. */
0472723a 211 int buflen = 1024;
c7a9b6e2 212 char *buffer = (char *) alloca (buflen);
67479a70
UD
213 struct group resultbuf;
214 struct group *grp;
a1c542bf 215 uid_t oldeuid = 0;
0472723a 216 bool use_malloc = false;
d67281a7 217
c7a9b6e2
UD
218 if (__builtin_expect (debug_level > 0, 0))
219 dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
d67281a7 220
a1c542bf
UD
221 if (secure[grpdb])
222 {
223 oldeuid = geteuid ();
224 seteuid (uid);
225 }
226
a4edafc1 227 while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
67479a70 228 && errno == ERANGE)
d67281a7 229 {
0472723a 230 char *old_buffer = buffer;
67479a70 231 errno = 0;
9caf4f1c 232#define INCR 1024
0472723a
UD
233
234 if (__builtin_expect (buflen > 32768, 0))
235 {
9caf4f1c 236 buflen += INCR;
0472723a
UD
237 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
238 if (buffer == NULL)
239 {
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;
246 }
247 use_malloc = true;
248 }
249 else
9caf4f1c
UD
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);
d67281a7 253 }
d67281a7 254
a1c542bf
UD
255 if (secure[grpdb])
256 seteuid (oldeuid);
257
258 cache_addgr (db, fd, req, key, grp, uid);
0472723a
UD
259
260 if (use_malloc)
261 free (buffer);
d67281a7
UD
262}
263
d67281a7 264
67479a70 265void
a1c542bf
UD
266addgrbygid (struct database *db, int fd, request_header *req,
267 void *key, uid_t uid)
67479a70
UD
268{
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. */
0472723a 273 int buflen = 1024;
c7a9b6e2 274 char *buffer = (char *) alloca (buflen);
67479a70
UD
275 struct group resultbuf;
276 struct group *grp;
a1c542bf 277 uid_t oldeuid = 0;
8e9b2075 278 char *ep;
0472723a
UD
279 gid_t gid = strtoul ((char *)key, &ep, 10);
280 bool use_malloc = false;
281
c7a9b6e2 282 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric gid */
8e9b2075
UD
283 {
284 if (debug_level > 0)
c7a9b6e2 285 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
8e9b2075
UD
286
287 errno = EINVAL;
288 return;
289 }
d67281a7 290
c7a9b6e2 291 if (__builtin_expect (debug_level > 0, 0))
67479a70 292 dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
d67281a7 293
a1c542bf
UD
294 if (secure[grpdb])
295 {
296 oldeuid = geteuid ();
297 seteuid (uid);
298 }
299
a4edafc1 300 while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
67479a70 301 && errno == ERANGE)
d67281a7 302 {
0472723a 303 char *old_buffer = buffer;
67479a70 304 errno = 0;
0472723a
UD
305
306 if (__builtin_expect (buflen > 32768, 0))
307 {
9caf4f1c 308 buflen += INCR;
0472723a
UD
309 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
310 if (buffer == NULL)
311 {
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;
318 }
319 use_malloc = true;
320 }
321 else
9caf4f1c
UD
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);
d67281a7 325 }
d67281a7 326
a1c542bf
UD
327 if (secure[grpdb])
328 seteuid (oldeuid);
329
330 cache_addgr (db, fd, req, key, grp, uid);
0472723a
UD
331
332 if (use_malloc)
333 free (buffer);
d67281a7 334}