Add dl-brk.c, dl-sbrk.c, and sys/personality.h.
[glibc.git] / nscd / pwdcache.c
blob9d88c88a37b218d48f24d24f3c226ffaf905f986
1 /* Cache handling for passwd lookup.
2 Copyright (C) 1998, 1999, 2000, 2001, 2002 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 <errno.h>
22 #include <error.h>
23 #include <pwd.h>
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <stackinfo.h>
34 #include "nscd.h"
35 #include "dbg_log.h"
37 /* This is the standard reply in case the service is disabled. */
38 static const pw_response_header disabled =
40 version: NSCD_VERSION,
41 found: -1,
42 pw_name_len: 0,
43 pw_passwd_len: 0,
44 pw_uid: -1,
45 pw_gid: -1,
46 pw_gecos_len: 0,
47 pw_dir_len: 0,
48 pw_shell_len: 0
51 /* This is the struct describing how to write this record. */
52 const struct iovec pwd_iov_disabled =
54 iov_base: (void *) &disabled,
55 iov_len: sizeof (disabled)
59 /* This is the standard reply in case we haven't found the dataset. */
60 static const pw_response_header notfound =
62 version: NSCD_VERSION,
63 found: 0,
64 pw_name_len: 0,
65 pw_passwd_len: 0,
66 pw_uid: -1,
67 pw_gid: -1,
68 pw_gecos_len: 0,
69 pw_dir_len: 0,
70 pw_shell_len: 0
73 /* This is the struct describing how to write this record. */
74 static const struct iovec iov_notfound =
76 iov_base: (void *) &notfound,
77 iov_len: sizeof (notfound)
81 struct passwddata
83 pw_response_header resp;
84 char strdata[0];
88 static void
89 cache_addpw (struct database *db, int fd, request_header *req, void *key,
90 struct passwd *pwd, uid_t owner)
92 ssize_t total;
93 ssize_t written;
94 time_t t = time (NULL);
96 if (pwd == NULL)
98 /* We have no data. This means we send the standard reply for this
99 case. */
100 void *copy;
102 total = sizeof (notfound);
104 written = writev (fd, &iov_notfound, 1);
106 copy = malloc (req->key_len);
107 if (copy == NULL)
108 error (EXIT_FAILURE, errno, _("while allocating key copy"));
109 memcpy (copy, key, req->key_len);
111 /* Compute the timeout time. */
112 t += db->negtimeout;
114 /* Now get the lock to safely insert the records. */
115 pthread_rwlock_rdlock (&db->lock);
117 cache_add (req->type, copy, req->key_len, &notfound,
118 sizeof (notfound), (void *) -1, 0, t, db, owner);
120 pthread_rwlock_unlock (&db->lock);
122 else
124 /* Determine the I/O structure. */
125 struct passwddata *data;
126 size_t pw_name_len = strlen (pwd->pw_name) + 1;
127 size_t pw_passwd_len = strlen (pwd->pw_passwd) + 1;
128 size_t pw_gecos_len = strlen (pwd->pw_gecos) + 1;
129 size_t pw_dir_len = strlen (pwd->pw_dir) + 1;
130 size_t pw_shell_len = strlen (pwd->pw_shell) + 1;
131 char *cp;
132 char buf[12];
133 ssize_t n;
135 /* We need this to insert the `byuid' entry. */
136 n = snprintf (buf, sizeof (buf), "%d", pwd->pw_uid) + 1;
138 /* We allocate all data in one memory block: the iov vector,
139 the response header and the dataset itself. */
140 total = (sizeof (struct passwddata) + pw_name_len + pw_passwd_len
141 + pw_gecos_len + pw_dir_len + pw_shell_len);
142 data = (struct passwddata *) malloc (total + n);
143 if (data == NULL)
144 /* There is no reason to go on. */
145 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
147 data->resp.found = 1;
148 data->resp.pw_name_len = pw_name_len;
149 data->resp.pw_passwd_len = pw_passwd_len;
150 data->resp.pw_uid = pwd->pw_uid;
151 data->resp.pw_gid = pwd->pw_gid;
152 data->resp.pw_gecos_len = pw_gecos_len;
153 data->resp.pw_dir_len = pw_dir_len;
154 data->resp.pw_shell_len = pw_shell_len;
156 cp = data->strdata;
158 /* Copy the strings over into the buffer. */
159 cp = mempcpy (cp, pwd->pw_name, pw_name_len);
160 cp = mempcpy (cp, pwd->pw_passwd, pw_passwd_len);
161 cp = mempcpy (cp, pwd->pw_gecos, pw_gecos_len);
162 cp = mempcpy (cp, pwd->pw_dir, pw_dir_len);
163 cp = mempcpy (cp, pwd->pw_shell, pw_shell_len);
165 /* Finally the stringified UID value. */
166 memcpy (cp, buf, n);
168 /* We write the dataset before inserting it to the database
169 since while inserting this thread might block and so would
170 unnecessarily let the receiver wait. */
171 written = TEMP_FAILURE_RETRY (write (fd, &data->resp, total));
173 /* Compute the timeout time. */
174 t += db->postimeout;
176 /* Now get the lock to safely insert the records. */
177 pthread_rwlock_rdlock (&db->lock);
179 /* We have to add the value for both, byname and byuid. */
180 cache_add (GETPWBYNAME, data->strdata, pw_name_len, data,
181 total, data, 0, t, db, owner);
183 cache_add (GETPWBYUID, cp, n, data, total, data, 1, t, db, owner);
185 pthread_rwlock_unlock (&db->lock);
188 if (__builtin_expect (written != total, 0) && debug_level > 0)
190 char buf[256];
191 dbg_log (_("short write in %s: %s"), __FUNCTION__,
192 strerror_r (errno, buf, sizeof (buf)));
197 void
198 addpwbyname (struct database *db, int fd, request_header *req,
199 void *key, uid_t c_uid)
201 /* Search for the entry matching the key. Please note that we don't
202 look again in the table whether the dataset is now available. We
203 simply insert it. It does not matter if it is in there twice. The
204 pruning function only will look at the timestamp. */
205 int buflen = 1024;
206 char *buffer = (char *) alloca (buflen);
207 struct passwd resultbuf;
208 struct passwd *pwd;
209 uid_t oldeuid = 0;
210 bool use_malloc = false;
212 if (__builtin_expect (debug_level > 0, 0))
213 dbg_log (_("Haven't found \"%s\" in password cache!"), (char *) key);
215 if (secure[pwddb])
217 oldeuid = geteuid ();
218 seteuid (c_uid);
221 while (__getpwnam_r (key, &resultbuf, buffer, buflen, &pwd) != 0
222 && errno == ERANGE)
224 char *old_buffer = buffer;
225 errno = 0;
226 buflen += 1024;
228 if (__builtin_expect (buflen > 32768, 0))
230 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
231 if (buffer == NULL)
233 /* We ran out of memory. We cannot do anything but
234 sending a negative response. In reality this should
235 never happen. */
236 pwd = NULL;
237 buffer = old_buffer;
238 break;
240 use_malloc = true;
242 else
244 buffer = (char *) alloca (buflen);
245 #if _STACK_GROWS_DOWN
246 if (buffer + buflen == old_buffer)
247 buflen = 2 * buflen - 1024;
248 #elif _STACK_GROWS_UP
249 if (old_buffer + buflen - 1024 == buffer)
251 buffer = old_buffer;
252 buflen = 2 * buflen - 1024;
254 #endif
258 if (secure[pwddb])
259 seteuid (oldeuid);
261 cache_addpw (db, fd, req, key, pwd, c_uid);
263 if (use_malloc)
264 free (buffer);
268 void
269 addpwbyuid (struct database *db, int fd, request_header *req,
270 void *key, uid_t c_uid)
272 /* Search for the entry matching the key. Please note that we don't
273 look again in the table whether the dataset is now available. We
274 simply insert it. It does not matter if it is in there twice. The
275 pruning function only will look at the timestamp. */
276 int buflen = 256;
277 char *buffer = (char *) alloca (buflen);
278 struct passwd resultbuf;
279 struct passwd *pwd;
280 uid_t oldeuid = 0;
281 char *ep;
282 uid_t uid = strtoul ((char *) key, &ep, 10);
283 bool use_malloc = false;
285 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric uid */
287 if (debug_level > 0)
288 dbg_log (_("Invalid numeric uid \"%s\"!"), (char *) key);
290 errno = EINVAL;
291 return;
294 if (__builtin_expect (debug_level > 0, 0))
295 dbg_log (_("Haven't found \"%d\" in password cache!"), uid);
297 if (secure[pwddb])
299 oldeuid = geteuid ();
300 seteuid (c_uid);
303 while (__getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0
304 && errno == ERANGE)
306 char *old_buffer = buffer;
307 errno = 0;
308 buflen += 1024;
310 if (__builtin_expect (buflen > 32768, 0))
312 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
313 if (buffer == NULL)
315 /* We ran out of memory. We cannot do anything but
316 sending a negative response. In reality this should
317 never happen. */
318 pwd = NULL;
319 buffer = old_buffer;
320 break;
322 use_malloc = true;
324 else
326 buffer = (char *) alloca (buflen);
327 #if _STACK_GROWS_DOWN
328 if (buffer + buflen == old_buffer)
329 buflen = 2 * buflen - 1024;
330 #elif _STACK_GROWS_UP
331 if (old_buffer + buflen - 1024 == buffer)
333 buffer = old_buffer;
334 buflen = 2 * buflen - 1024;
336 #endif
340 if (secure[pwddb])
341 seteuid (oldeuid);
343 cache_addpw (db, fd, req, key, pwd, c_uid);
345 if (use_malloc)
346 free (buffer);