]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/grpcache.c
Fix comment.
[thirdparty/glibc.git] / nscd / grpcache.c
CommitLineData
67479a70 1/* Cache handling for group lookup.
98e75a1c 2 Copyright (C) 1998, 1999, 2000, 2001 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
UD
20
21#include <errno.h>
67479a70 22#include <error.h>
d67281a7 23#include <grp.h>
67479a70
UD
24#include <stddef.h>
25#include <stdio.h>
3107c0c5 26#include <stdint.h>
da2d1bc5 27#include <stdlib.h>
d67281a7 28#include <string.h>
ba9234d9 29#include <unistd.h>
4360eafd 30#include <libintl.h>
d67281a7 31
d67281a7 32#include "nscd.h"
67479a70 33#include "dbg_log.h"
d67281a7 34
67479a70
UD
35/* This is the standard reply in case the service is disabled. */
36static const gr_response_header disabled =
d67281a7 37{
67479a70
UD
38 version: NSCD_VERSION,
39 found: -1,
40 gr_name_len: 0,
41 gr_passwd_len: 0,
42 gr_gid: -1,
43 gr_mem_cnt: 0,
d67281a7 44};
d67281a7 45
67479a70
UD
46/* This is the struct describing how to write this record. */
47const struct iovec grp_iov_disabled =
d67281a7 48{
67479a70
UD
49 iov_base: (void *) &disabled,
50 iov_len: sizeof (disabled)
d67281a7 51};
d67281a7 52
67479a70
UD
53
54/* This is the standard reply in case we haven't found the dataset. */
55static const gr_response_header notfound =
d67281a7 56{
67479a70
UD
57 version: NSCD_VERSION,
58 found: 0,
59 gr_name_len: 0,
60 gr_passwd_len: 0,
61 gr_gid: -1,
62 gr_mem_cnt: 0,
d67281a7 63};
d67281a7 64
67479a70
UD
65/* This is the struct describing how to write this record. */
66static const struct iovec iov_notfound =
d67281a7 67{
67479a70
UD
68 iov_base: (void *) &notfound,
69 iov_len: sizeof (notfound)
70};
d67281a7 71
d67281a7 72
67479a70 73struct groupdata
d67281a7 74{
67479a70
UD
75 gr_response_header resp;
76 char strdata[0];
77};
d67281a7 78
d67281a7 79
67479a70
UD
80static void
81cache_addgr (struct database *db, int fd, request_header *req, void *key,
a1c542bf 82 struct group *grp, uid_t owner)
d67281a7 83{
67479a70
UD
84 ssize_t total;
85 ssize_t written;
86 time_t t = time (NULL);
d67281a7 87
67479a70 88 if (grp == NULL)
d67281a7 89 {
67479a70
UD
90 /* We have no data. This means we send the standard reply for this
91 case. */
92 void *copy;
d67281a7 93
67479a70 94 total = sizeof (notfound);
d67281a7 95
67479a70 96 written = writev (fd, &iov_notfound, 1);
d67281a7 97
67479a70
UD
98 copy = malloc (req->key_len);
99 if (copy == NULL)
100 error (EXIT_FAILURE, errno, _("while allocating key copy"));
101 memcpy (copy, key, req->key_len);
d67281a7 102
67479a70
UD
103 /* Compute the timeout time. */
104 t += db->negtimeout;
14e9dd67 105
67479a70
UD
106 /* Now get the lock to safely insert the records. */
107 pthread_rwlock_rdlock (&db->lock);
d67281a7 108
d0db5f48 109 cache_add (req->type, copy, req->key_len, &notfound,
a1c542bf 110 sizeof (notfound), (void *) -1, 0, t, db, owner);
d67281a7 111
67479a70 112 pthread_rwlock_unlock (&db->lock);
d67281a7 113 }
ba9234d9
UD
114 else
115 {
67479a70
UD
116 /* Determine the I/O structure. */
117 struct groupdata *data;
118 size_t gr_name_len = strlen (grp->gr_name) + 1;
119 size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
120 size_t gr_mem_cnt = 0;
3107c0c5 121 uint32_t *gr_mem_len;
67479a70
UD
122 size_t gr_mem_len_total = 0;
123 char *gr_name;
124 char *cp;
125 char buf[12];
126 ssize_t n;
127 size_t cnt;
128
129 /* We need this to insert the `bygid' entry. */
130 n = snprintf (buf, sizeof (buf), "%d", grp->gr_gid) + 1;
131
132 /* Determine the length of all members. */
133 while (grp->gr_mem[gr_mem_cnt])
134 ++gr_mem_cnt;
3107c0c5 135 gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
67479a70
UD
136 for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
137 {
138 gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
139 gr_mem_len_total += gr_mem_len[gr_mem_cnt];
140 }
ba9234d9 141
67479a70
UD
142 /* We allocate all data in one memory block: the iov vector,
143 the response header and the dataset itself. */
144 total = (sizeof (struct groupdata)
3107c0c5 145 + gr_mem_cnt * sizeof (uint32_t)
67479a70
UD
146 + gr_name_len + gr_passwd_len + gr_mem_len_total);
147 data = (struct groupdata *) malloc (total + n);
148 if (data == NULL)
149 /* There is no reason to go on. */
150 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
d67281a7 151
67479a70
UD
152 data->resp.found = 1;
153 data->resp.gr_name_len = gr_name_len;
154 data->resp.gr_passwd_len = gr_passwd_len;
155 data->resp.gr_gid = grp->gr_gid;
156 data->resp.gr_mem_cnt = gr_mem_cnt;
d67281a7 157
67479a70 158 cp = data->strdata;
d67281a7 159
67479a70 160 /* This is the member string length array. */
3107c0c5 161 cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
0a55a284
UD
162 gr_name = cp;
163 cp = mempcpy (cp, grp->gr_name, gr_name_len);
67479a70 164 cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
d67281a7 165
67479a70
UD
166 for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
167 cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
d67281a7 168
67479a70
UD
169 /* Finally the stringified GID value. */
170 memcpy (cp, buf, n);
d67281a7 171
67479a70 172 /* Write the result. */
23700036 173 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
d67281a7 174
67479a70
UD
175 /* Compute the timeout time. */
176 t += db->postimeout;
d67281a7 177
67479a70
UD
178 /* Now get the lock to safely insert the records. */
179 pthread_rwlock_rdlock (&db->lock);
14e9dd67 180
67479a70
UD
181 /* We have to add the value for both, byname and byuid. */
182 cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
a1c542bf 183 total, data, 0, t, db, owner);
d67281a7 184
a1c542bf 185 cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
d67281a7 186
67479a70 187 pthread_rwlock_unlock (&db->lock);
d67281a7
UD
188 }
189
23700036 190 if (__builtin_expect (written != total, 0) && debug_level > 0)
d67281a7 191 {
67479a70
UD
192 char buf[256];
193 dbg_log (_("short write in %s: %s"), __FUNCTION__,
194 strerror_r (errno, buf, sizeof (buf)));
d67281a7 195 }
d67281a7
UD
196}
197
d67281a7 198
67479a70 199void
a1c542bf
UD
200addgrbyname (struct database *db, int fd, request_header *req,
201 void *key, uid_t uid)
67479a70
UD
202{
203 /* Search for the entry matching the key. Please note that we don't
204 look again in the table whether the dataset is now available. We
205 simply insert it. It does not matter if it is in there twice. The
206 pruning function only will look at the timestamp. */
207 int buflen = 256;
208 char *buffer = alloca (buflen);
209 struct group resultbuf;
210 struct group *grp;
a1c542bf 211 uid_t oldeuid = 0;
d67281a7 212
67479a70 213 if (debug_level > 0)
0a12bf88 214 dbg_log (_("Haven't found \"%s\" in group cache!"), (char *)key);
d67281a7 215
a1c542bf
UD
216 if (secure[grpdb])
217 {
218 oldeuid = geteuid ();
219 seteuid (uid);
220 }
221
a4edafc1 222 while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
67479a70 223 && errno == ERANGE)
d67281a7 224 {
67479a70
UD
225 errno = 0;
226 buflen += 256;
227 buffer = alloca (buflen);
d67281a7 228 }
d67281a7 229
a1c542bf
UD
230 if (secure[grpdb])
231 seteuid (oldeuid);
232
233 cache_addgr (db, fd, req, key, grp, uid);
d67281a7
UD
234}
235
d67281a7 236
67479a70 237void
a1c542bf
UD
238addgrbygid (struct database *db, int fd, request_header *req,
239 void *key, uid_t uid)
67479a70
UD
240{
241 /* Search for the entry matching the key. Please note that we don't
242 look again in the table whether the dataset is now available. We
243 simply insert it. It does not matter if it is in there twice. The
244 pruning function only will look at the timestamp. */
245 int buflen = 256;
246 char *buffer = alloca (buflen);
247 struct group resultbuf;
248 struct group *grp;
a1c542bf 249 uid_t oldeuid = 0;
8e9b2075
UD
250 char *ep;
251 gid_t gid = strtoul ((char *)key, &ep, 10);
252
253 if (*(char*)key == '\0' || *ep != '\0') /* invalid numeric gid */
254 {
255 if (debug_level > 0)
256 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *)key);
257
258 errno = EINVAL;
259 return;
260 }
d67281a7 261
67479a70
UD
262 if (debug_level > 0)
263 dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
d67281a7 264
a1c542bf
UD
265 if (secure[grpdb])
266 {
267 oldeuid = geteuid ();
268 seteuid (uid);
269 }
270
a4edafc1 271 while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
67479a70 272 && errno == ERANGE)
d67281a7 273 {
67479a70
UD
274 errno = 0;
275 buflen += 256;
276 buffer = alloca (buflen);
d67281a7 277 }
d67281a7 278
a1c542bf
UD
279 if (secure[grpdb])
280 seteuid (oldeuid);
281
282 cache_addgr (db, fd, req, key, grp, uid);
d67281a7 283}