]> sourceware.org Git - glibc.git/blob - nscd/pwdcache.c
Update.
[glibc.git] / nscd / pwdcache.c
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.
5
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.
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
14 Library General Public License for more details.
15
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. */
20
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>
30
31 #include "nscd.h"
32 #include "dbg_log.h"
33
34 /* This is the standard reply in case the service is disabled. */
35 static const pw_response_header disabled =
36 {
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
46 };
47
48 /* This is the struct describing how to write this record. */
49 const struct iovec pwd_iov_disabled =
50 {
51 iov_base: (void *) &disabled,
52 iov_len: sizeof (disabled)
53 };
54
55
56 /* This is the standard reply in case we haven't found the dataset. */
57 static const pw_response_header notfound =
58 {
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
68 };
69
70 /* This is the struct describing how to write this record. */
71 static const struct iovec iov_notfound =
72 {
73 iov_base: (void *) &notfound,
74 iov_len: sizeof (notfound)
75 };
76
77
78 struct passwddata
79 {
80 pw_response_header resp;
81 char strdata[0];
82 };
83
84
85 static void
86 cache_addpw (struct database *db, int fd, request_header *req, void *key,
87 struct passwd *pwd)
88 {
89 ssize_t total;
90 ssize_t written;
91 time_t t = time (NULL);
92
93 if (pwd == NULL)
94 {
95 /* We have no data. This means we send the standard reply for this
96 case. */
97 void *copy;
98
99 total = sizeof (notfound);
100
101 written = writev (fd, &iov_notfound, 1);
102
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);
107
108 /* Compute the timeout time. */
109 t += db->negtimeout;
110
111 /* Now get the lock to safely insert the records. */
112 pthread_rwlock_rdlock (&db->lock);
113
114 cache_add (req->type, copy, req->key_len, &iov_notfound,
115 sizeof (notfound), (void *) -1, 0, t, db);
116
117 pthread_rwlock_unlock (&db->lock);
118 }
119 else
120 {
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;
131
132 /* We need this to insert the `byuid' entry. */
133 n = snprintf (buf, sizeof (buf), "%d", pwd->pw_uid) + 1;
134
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"));
143
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;
152
153 cp = data->strdata;
154
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);
161
162 /* Finally the stringified UID value. */
163 memcpy (cp, buf, n);
164
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);
169
170 /* Compute the timeout time. */
171 t += db->postimeout;
172
173 /* Now get the lock to safely insert the records. */
174 pthread_rwlock_rdlock (&db->lock);
175
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);
179
180 cache_add (GETPWBYUID, cp, n, data, total, data, 1, t, db);
181
182 pthread_rwlock_unlock (&db->lock);
183 }
184
185 if (written != total)
186 {
187 char buf[256];
188 dbg_log (_("short write in %s: %s"), __FUNCTION__,
189 strerror_r (errno, buf, sizeof (buf)));
190 }
191 }
192
193
194 void
195 addpwbyname (struct database *db, int fd, request_header *req, void *key)
196 {
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;
205
206 if (debug_level > 0)
207 dbg_log (_("Haven't found \"%s\" in password cache!"), key);
208
209 while (getpwnam_r (key, &resultbuf, buffer, buflen, &pwd) != 0
210 && errno == ERANGE)
211 {
212 errno = 0;
213 buflen += 256;
214 buffer = alloca (buflen);
215 }
216
217 cache_addpw (db, fd, req, key, pwd);
218 }
219
220
221 void
222 addpwbyuid (struct database *db, int fd, request_header *req, void *key)
223 {
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);
233
234 if (debug_level > 0)
235 dbg_log (_("Haven't found \"%d\" in password cache!"), uid);
236
237 while (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0
238 && errno == ERANGE)
239 {
240 errno = 0;
241 buflen += 256;
242 buffer = alloca (buflen);
243 }
244
245 cache_addpw (db, fd, req, key, pwd);
246 }
This page took 0.056366 seconds and 6 git commands to generate.