]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/grpcache.c
(cache_addpw): Use cope of original key in hash entry with alternative key.
[thirdparty/glibc.git] / nscd / grpcache.c
CommitLineData
67479a70 1/* Cache handling for group lookup.
99bb9f42 2 Copyright (C) 1998-2002, 2003, 2004 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
d67281a7 68
67479a70 69struct groupdata
d67281a7 70{
67479a70
UD
71 gr_response_header resp;
72 char strdata[0];
73};
d67281a7 74
d67281a7 75
67479a70
UD
76static void
77cache_addgr (struct database *db, int fd, request_header *req, void *key,
dc630ccc 78 struct group *grp, uid_t owner, int type)
d67281a7 79{
67479a70
UD
80 ssize_t total;
81 ssize_t written;
82 time_t t = time (NULL);
d67281a7 83
67479a70 84 if (grp == NULL)
d67281a7 85 {
67479a70
UD
86 /* We have no data. This means we send the standard reply for this
87 case. */
67479a70 88 total = sizeof (notfound);
d67281a7 89
99bb9f42 90 written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
d67281a7 91
99bb9f42
UD
92 void *copy = malloc (req->key_len);
93 /* If we cannot allocate memory simply do not cache the information. */
94 if (copy != NULL)
95 {
96 memcpy (copy, key, req->key_len);
d67281a7 97
99bb9f42
UD
98 /* Compute the timeout time. */
99 t += db->negtimeout;
14e9dd67 100
99bb9f42
UD
101 /* Now get the lock to safely insert the records. */
102 pthread_rwlock_rdlock (&db->lock);
d67281a7 103
99bb9f42
UD
104 cache_add (req->type, copy, req->key_len, &notfound,
105 sizeof (notfound), (void *) -1, 0, t, db, owner);
d67281a7 106
99bb9f42
UD
107 pthread_rwlock_unlock (&db->lock);
108 }
d67281a7 109 }
ba9234d9
UD
110 else
111 {
67479a70
UD
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;
3107c0c5 117 uint32_t *gr_mem_len;
67479a70
UD
118 size_t gr_mem_len_total = 0;
119 char *gr_name;
120 char *cp;
121 char buf[12];
122 ssize_t n;
123 size_t cnt;
124
125 /* We need this to insert the `bygid' entry. */
126 n = snprintf (buf, sizeof (buf), "%d", grp->gr_gid) + 1;
127
128 /* Determine the length of all members. */
129 while (grp->gr_mem[gr_mem_cnt])
130 ++gr_mem_cnt;
3107c0c5 131 gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
67479a70
UD
132 for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
133 {
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];
136 }
ba9234d9 137
67479a70
UD
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)
3107c0c5 141 + gr_mem_cnt * sizeof (uint32_t)
67479a70
UD
142 + gr_name_len + gr_passwd_len + gr_mem_len_total);
143 data = (struct groupdata *) malloc (total + n);
144 if (data == NULL)
145 /* There is no reason to go on. */
146 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
d67281a7 147
fe453812 148 data->resp.version = NSCD_VERSION;
67479a70
UD
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;
d67281a7 154
67479a70 155 cp = data->strdata;
d67281a7 156
67479a70 157 /* This is the member string length array. */
3107c0c5 158 cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
0a55a284
UD
159 gr_name = cp;
160 cp = mempcpy (cp, grp->gr_name, gr_name_len);
67479a70 161 cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
d67281a7 162
67479a70
UD
163 for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
164 cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
d67281a7 165
67479a70
UD
166 /* Finally the stringified GID value. */
167 memcpy (cp, buf, n);
d67281a7 168
67479a70 169 /* Write the result. */
23700036 170 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
d67281a7 171
67479a70
UD
172 /* Compute the timeout time. */
173 t += db->postimeout;
d67281a7 174
67479a70
UD
175 /* Now get the lock to safely insert the records. */
176 pthread_rwlock_rdlock (&db->lock);
14e9dd67 177
67479a70
UD
178 /* We have to add the value for both, byname and byuid. */
179 cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
a1c542bf 180 total, data, 0, t, db, owner);
d67281a7 181
dc630ccc
UD
182 /* If the key is different from the name add a separate entry. */
183 if (type == GETGRBYNAME && strcmp (key, gr_name) != 0)
184 cache_add (GETGRBYNAME, key, strlen (key) + 1, data,
185 total, data, 0, t, db, owner);
186
a1c542bf 187 cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
d67281a7 188
67479a70 189 pthread_rwlock_unlock (&db->lock);
d67281a7
UD
190 }
191
23700036 192 if (__builtin_expect (written != total, 0) && debug_level > 0)
d67281a7 193 {
67479a70
UD
194 char buf[256];
195 dbg_log (_("short write in %s: %s"), __FUNCTION__,
196 strerror_r (errno, buf, sizeof (buf)));
d67281a7 197 }
d67281a7
UD
198}
199
d67281a7 200
67479a70 201void
a1c542bf
UD
202addgrbyname (struct database *db, int fd, request_header *req,
203 void *key, uid_t uid)
67479a70
UD
204{
205 /* Search for the entry matching the key. Please note that we don't
206 look again in the table whether the dataset is now available. We
207 simply insert it. It does not matter if it is in there twice. The
208 pruning function only will look at the timestamp. */
0472723a 209 int buflen = 1024;
c7a9b6e2 210 char *buffer = (char *) alloca (buflen);
67479a70
UD
211 struct group resultbuf;
212 struct group *grp;
a1c542bf 213 uid_t oldeuid = 0;
0472723a 214 bool use_malloc = false;
d67281a7 215
c7a9b6e2
UD
216 if (__builtin_expect (debug_level > 0, 0))
217 dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
d67281a7 218
a1c542bf
UD
219 if (secure[grpdb])
220 {
221 oldeuid = geteuid ();
222 seteuid (uid);
223 }
224
a4edafc1 225 while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
67479a70 226 && errno == ERANGE)
d67281a7 227 {
0472723a 228 char *old_buffer = buffer;
67479a70 229 errno = 0;
9caf4f1c 230#define INCR 1024
0472723a
UD
231
232 if (__builtin_expect (buflen > 32768, 0))
233 {
9caf4f1c 234 buflen += INCR;
0472723a
UD
235 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
236 if (buffer == NULL)
237 {
238 /* We ran out of memory. We cannot do anything but
239 sending a negative response. In reality this should
240 never happen. */
241 grp = NULL;
242 buffer = old_buffer;
243 break;
244 }
245 use_malloc = true;
246 }
247 else
9caf4f1c
UD
248 /* Allocate a new buffer on the stack. If possible combine it
249 with the previously allocated buffer. */
250 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
d67281a7 251 }
d67281a7 252
a1c542bf
UD
253 if (secure[grpdb])
254 seteuid (oldeuid);
255
dc630ccc 256 cache_addgr (db, fd, req, key, grp, uid, GETGRBYNAME);
0472723a
UD
257
258 if (use_malloc)
259 free (buffer);
d67281a7
UD
260}
261
d67281a7 262
67479a70 263void
a1c542bf
UD
264addgrbygid (struct database *db, int fd, request_header *req,
265 void *key, uid_t uid)
67479a70
UD
266{
267 /* Search for the entry matching the key. Please note that we don't
268 look again in the table whether the dataset is now available. We
269 simply insert it. It does not matter if it is in there twice. The
270 pruning function only will look at the timestamp. */
0472723a 271 int buflen = 1024;
c7a9b6e2 272 char *buffer = (char *) alloca (buflen);
67479a70
UD
273 struct group resultbuf;
274 struct group *grp;
a1c542bf 275 uid_t oldeuid = 0;
8e9b2075 276 char *ep;
0472723a
UD
277 gid_t gid = strtoul ((char *)key, &ep, 10);
278 bool use_malloc = false;
279
c7a9b6e2 280 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric gid */
8e9b2075
UD
281 {
282 if (debug_level > 0)
c7a9b6e2 283 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
8e9b2075
UD
284
285 errno = EINVAL;
286 return;
287 }
d67281a7 288
c7a9b6e2 289 if (__builtin_expect (debug_level > 0, 0))
67479a70 290 dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
d67281a7 291
a1c542bf
UD
292 if (secure[grpdb])
293 {
294 oldeuid = geteuid ();
295 seteuid (uid);
296 }
297
a4edafc1 298 while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
67479a70 299 && errno == ERANGE)
d67281a7 300 {
0472723a 301 char *old_buffer = buffer;
67479a70 302 errno = 0;
0472723a
UD
303
304 if (__builtin_expect (buflen > 32768, 0))
305 {
9caf4f1c 306 buflen += INCR;
0472723a
UD
307 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
308 if (buffer == NULL)
309 {
310 /* We ran out of memory. We cannot do anything but
311 sending a negative response. In reality this should
312 never happen. */
313 grp = NULL;
314 buffer = old_buffer;
315 break;
316 }
317 use_malloc = true;
318 }
319 else
9caf4f1c
UD
320 /* Allocate a new buffer on the stack. If possible combine it
321 with the previously allocated buffer. */
322 buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
d67281a7 323 }
d67281a7 324
a1c542bf
UD
325 if (secure[grpdb])
326 seteuid (oldeuid);
327
dc630ccc 328 cache_addgr (db, fd, req, key, grp, uid, GETGRBYGID);
0472723a
UD
329
330 if (use_malloc)
331 free (buffer);
d67281a7 332}