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
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
,
68 /* This is the struct describing how to write this record. */
69 static const struct iovec iov_notfound
=
71 .iov_base
= (void *) ¬found
,
72 .iov_len
= sizeof (notfound
)
78 gr_response_header resp
;
84 cache_addgr (struct database
*db
, int fd
, request_header
*req
, void *key
,
85 struct group
*grp
, uid_t owner
)
89 time_t t
= time (NULL
);
93 /* We have no data. This means we send the standard reply for this
97 total
= sizeof (notfound
);
99 written
= TEMP_FAILURE_RETRY (writev (fd
, &iov_notfound
, 1));
101 copy
= malloc (req
->key_len
);
103 error (EXIT_FAILURE
, errno
, _("while allocating key copy"));
104 memcpy (copy
, key
, req
->key_len
);
106 /* Compute the timeout time. */
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
, ¬found
,
113 sizeof (notfound
), (void *) -1, 0, t
, db
, owner
);
115 pthread_rwlock_unlock (&db
->lock
);
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;
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
])
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
);
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
;
164 /* This is the member string length array. */
165 cp
= mempcpy (cp
, gr_mem_len
, gr_mem_cnt
* sizeof (uint32_t));
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. */
176 /* Write the result. */
177 written
= TEMP_FAILURE_RETRY (write (fd
, &data
->resp
, total
));
179 /* Compute the timeout time. */
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)
197 dbg_log (_("short write in %s: %s"), __FUNCTION__
,
198 strerror_r (errno
, buf
, sizeof (buf
)));
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. */
212 char *buffer
= (char *) alloca (buflen
);
213 struct group resultbuf
;
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
);
223 oldeuid
= geteuid ();
227 while (__getgrnam_r (key
, &resultbuf
, buffer
, buflen
, &grp
) != 0
230 char *old_buffer
= buffer
;
234 if (__builtin_expect (buflen
> 32768, 0))
237 buffer
= (char *) realloc (use_malloc
? buffer
: NULL
, buflen
);
240 /* We ran out of memory. We cannot do anything but
241 sending a negative response. In reality this should
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
);
258 cache_addgr (db
, fd
, req
, key
, grp
, uid
);
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. */
274 char *buffer
= (char *) alloca (buflen
);
275 struct group resultbuf
;
279 gid_t gid
= strtoul ((char *)key
, &ep
, 10);
280 bool use_malloc
= false;
282 if (*(char *) key
== '\0' || *ep
!= '\0') /* invalid numeric gid */
285 dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key
);
291 if (__builtin_expect (debug_level
> 0, 0))
292 dbg_log (_("Haven't found \"%d\" in group cache!"), gid
);
296 oldeuid
= geteuid ();
300 while (__getgrgid_r (gid
, &resultbuf
, buffer
, buflen
, &grp
) != 0
303 char *old_buffer
= buffer
;
306 if (__builtin_expect (buflen
> 32768, 0))
309 buffer
= (char *) realloc (use_malloc
? buffer
: NULL
, buflen
);
312 /* We ran out of memory. We cannot do anything but
313 sending a negative response. In reality this should
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
);
330 cache_addgr (db
, fd
, req
, key
, grp
, uid
);