Update.
[glibc.git] / nscd / pwdcache.c
blob5bf89a75bacc7806038bd8b8532c91cdb8548750
1 /* Cache handling for passwd lookup.
2 Copyright (C) 1998 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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <errno.h>
22 #include <error.h>
23 #include <pwd.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
31 #include "nscd.h"
32 #include "dbg_log.h"
34 /* This is the standard reply in case the service is disabled. */
35 static const pw_response_header disabled =
37 version: NSCD_VERSION,
38 found: -1,
39 pw_name_len: 0,
40 pw_passwd_len: 0,
41 pw_uid: -1,
42 pw_gid: -1,
43 pw_gecos_len: 0,
44 pw_dir_len: 0,
45 pw_shell_len: 0
48 /* This is the struct describing how to write this record. */
49 const struct iovec pwd_iov_disabled =
51 iov_base: (void *) &disabled,
52 iov_len: sizeof (disabled)
56 /* This is the standard reply in case we haven't found the dataset. */
57 static const pw_response_header notfound =
59 version: NSCD_VERSION,
60 found: 0,
61 pw_name_len: 0,
62 pw_passwd_len: 0,
63 pw_uid: -1,
64 pw_gid: -1,
65 pw_gecos_len: 0,
66 pw_dir_len: 0,
67 pw_shell_len: 0
70 /* This is the struct describing how to write this record. */
71 static const struct iovec iov_notfound =
73 iov_base: (void *) &notfound,
74 iov_len: sizeof (notfound)
78 struct passwddata
80 pw_response_header resp;
81 char strdata[0];
85 static void
86 cache_addpw (struct database *db, int fd, request_header *req, void *key,
87 struct passwd *pwd)
89 ssize_t total;
90 ssize_t written;
91 time_t t = time (NULL);
93 if (pwd == NULL)
95 /* We have no data. This means we send the standard reply for this
96 case. */
97 void *copy;
99 total = sizeof (notfound);
101 written = writev (fd, &iov_notfound, 1);
103 copy = malloc (req->key_len);
104 if (copy == NULL)
105 error (EXIT_FAILURE, errno, _("while allocating key copy"));
106 memcpy (copy, key, req->key_len);
108 /* Compute the timeout time. */
109 t += db->negtimeout;
111 /* Now get the lock to safely insert the records. */
112 pthread_rwlock_rdlock (&db->lock);
114 cache_add (req->type, copy, req->key_len, &iov_notfound,
115 sizeof (notfound), (void *) -1, 0, t, db);
117 pthread_rwlock_unlock (&db->lock);
119 else
121 /* Determine the I/O structure. */
122 struct passwddata *data;
123 size_t pw_name_len = strlen (pwd->pw_name) + 1;
124 size_t pw_passwd_len = strlen (pwd->pw_passwd) + 1;
125 size_t pw_gecos_len = strlen (pwd->pw_gecos) + 1;
126 size_t pw_dir_len = strlen (pwd->pw_dir) + 1;
127 size_t pw_shell_len = strlen (pwd->pw_shell) + 1;
128 char *cp;
129 char buf[12];
130 ssize_t n;
132 /* We need this to insert the `byuid' entry. */
133 n = snprintf (buf, sizeof (buf), "%d", pwd->pw_uid) + 1;
135 /* We allocate all data in one memory block: the iov vector,
136 the response header and the dataset itself. */
137 total = (sizeof (struct passwddata) + pw_name_len + pw_passwd_len
138 + pw_gecos_len + pw_dir_len + pw_shell_len);
139 data = (struct passwddata *) malloc (total + n);
140 if (data == NULL)
141 /* There is no reason to go on. */
142 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
144 data->resp.found = 1;
145 data->resp.pw_name_len = pw_name_len;
146 data->resp.pw_passwd_len = pw_passwd_len;
147 data->resp.pw_uid = pwd->pw_uid;
148 data->resp.pw_gid = pwd->pw_gid;
149 data->resp.pw_gecos_len = pw_gecos_len;
150 data->resp.pw_dir_len = pw_dir_len;
151 data->resp.pw_shell_len = pw_shell_len;
153 cp = data->strdata;
155 /* Copy the strings over into the buffer. */
156 cp = mempcpy (cp, pwd->pw_name, pw_name_len);
157 cp = mempcpy (cp, pwd->pw_passwd, pw_passwd_len);
158 cp = mempcpy (cp, pwd->pw_gecos, pw_gecos_len);
159 cp = mempcpy (cp, pwd->pw_dir, pw_dir_len);
160 cp = mempcpy (cp, pwd->pw_shell, pw_shell_len);
162 /* Finally the stringified UID value. */
163 memcpy (cp, buf, n);
165 /* We write the dataset before inserting it to the database
166 since while inserting this thread might block and so would
167 unnecessarily let the receiver wait. */
168 written = write (fd, &data->resp, total);
170 /* Compute the timeout time. */
171 t += db->postimeout;
173 /* Now get the lock to safely insert the records. */
174 pthread_rwlock_rdlock (&db->lock);
176 /* We have to add the value for both, byname and byuid. */
177 cache_add (GETPWBYNAME, data->strdata, pw_name_len, data,
178 total, data, 0, t, db);
180 cache_add (GETPWBYUID, cp, n, data, total, data, 1, t, db);
182 pthread_rwlock_unlock (&db->lock);
185 if (written != total)
187 char buf[256];
188 dbg_log (_("short write in %s: %s"), __FUNCTION__,
189 strerror_r (errno, buf, sizeof (buf)));
194 void
195 addpwbyname (struct database *db, int fd, request_header *req, void *key)
197 /* Search for the entry matching the key. Please note that we don't
198 look again in the table whether the dataset is now available. We
199 simply insert it. It does not matter if it is in there twice. The
200 pruning function only will look at the timestamp. */
201 int buflen = 256;
202 char *buffer = alloca (buflen);
203 struct passwd resultbuf;
204 struct passwd *pwd;
206 if (debug_level > 0)
207 dbg_log (_("Haven't found \"%s\" in password cache!"), key);
209 while (getpwnam_r (key, &resultbuf, buffer, buflen, &pwd) != 0
210 && errno == ERANGE)
212 errno = 0;
213 buflen += 256;
214 buffer = alloca (buflen);
217 cache_addpw (db, fd, req, key, pwd);
221 void
222 addpwbyuid (struct database *db, int fd, request_header *req, void *key)
224 /* Search for the entry matching the key. Please note that we don't
225 look again in the table whether the dataset is now available. We
226 simply insert it. It does not matter if it is in there twice. The
227 pruning function only will look at the timestamp. */
228 int buflen = 256;
229 char *buffer = alloca (buflen);
230 struct passwd resultbuf;
231 struct passwd *pwd;
232 uid_t uid = atol (key);
234 if (debug_level > 0)
235 dbg_log (_("Haven't found \"%d\" in password cache!"), uid);
237 while (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0
238 && errno == ERANGE)
240 errno = 0;
241 buflen += 256;
242 buffer = alloca (buflen);
245 cache_addpw (db, fd, req, key, pwd);