pwcache.c revision 1.16 1 1.16 lukem /* $NetBSD: pwcache.c,v 1.16 2002/01/04 14:50:29 lukem Exp $ */
2 1.4 cgd
3 1.10 mycroft /*-
4 1.10 mycroft * Copyright (c) 1992 Keith Muller.
5 1.10 mycroft * Copyright (c) 1992, 1993
6 1.4 cgd * The Regents of the University of California. All rights reserved.
7 1.1 cgd *
8 1.10 mycroft * This code is derived from software contributed to Berkeley by
9 1.10 mycroft * Keith Muller of the University of California, San Diego.
10 1.10 mycroft *
11 1.1 cgd * Redistribution and use in source and binary forms, with or without
12 1.1 cgd * modification, are permitted provided that the following conditions
13 1.1 cgd * are met:
14 1.1 cgd * 1. Redistributions of source code must retain the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer.
16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 cgd * notice, this list of conditions and the following disclaimer in the
18 1.1 cgd * documentation and/or other materials provided with the distribution.
19 1.1 cgd * 3. All advertising materials mentioning features or use of this software
20 1.1 cgd * must display the following acknowledgement:
21 1.1 cgd * This product includes software developed by the University of
22 1.1 cgd * California, Berkeley and its contributors.
23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
24 1.1 cgd * may be used to endorse or promote products derived from this software
25 1.1 cgd * without specific prior written permission.
26 1.1 cgd *
27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.1 cgd * SUCH DAMAGE.
38 1.1 cgd */
39 1.1 cgd
40 1.7 christos #include <sys/cdefs.h>
41 1.15 msaitoh #if defined(LIBC_SCCS) && !defined(lint)
42 1.4 cgd #if 0
43 1.10 mycroft static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
44 1.4 cgd #else
45 1.16 lukem __RCSID("$NetBSD: pwcache.c,v 1.16 2002/01/04 14:50:29 lukem Exp $");
46 1.4 cgd #endif
47 1.15 msaitoh #endif /* LIBC_SCCS and not lint */
48 1.1 cgd
49 1.8 jtc #include "namespace.h"
50 1.10 mycroft
51 1.1 cgd #include <sys/types.h>
52 1.6 sommerfe #include <sys/param.h>
53 1.4 cgd
54 1.13 lukem #include <assert.h>
55 1.4 cgd #include <grp.h>
56 1.1 cgd #include <pwd.h>
57 1.1 cgd #include <stdio.h>
58 1.10 mycroft #include <stdlib.h>
59 1.5 jtc #include <string.h>
60 1.10 mycroft #include <unistd.h>
61 1.10 mycroft
62 1.10 mycroft #include "pwcache.h"
63 1.8 jtc
64 1.8 jtc #ifdef __weak_alias
65 1.14 mycroft __weak_alias(user_from_uid,_user_from_uid)
66 1.14 mycroft __weak_alias(group_from_gid,_group_from_gid)
67 1.8 jtc #endif
68 1.1 cgd
69 1.10 mycroft /*
70 1.10 mycroft * routines that control user, group, uid and gid caches (for the archive
71 1.10 mycroft * member print routine).
72 1.10 mycroft * IMPORTANT:
73 1.10 mycroft * these routines cache BOTH hits and misses, a major performance improvement
74 1.10 mycroft */
75 1.10 mycroft
76 1.10 mycroft static int pwopn = 0; /* is password file open */
77 1.10 mycroft static int gropn = 0; /* is group file open */
78 1.10 mycroft static UIDC **uidtb = NULL; /* uid to name cache */
79 1.10 mycroft static GIDC **gidtb = NULL; /* gid to name cache */
80 1.10 mycroft static UIDC **usrtb = NULL; /* user name to uid cache */
81 1.10 mycroft static GIDC **grptb = NULL; /* group name to gid cache */
82 1.10 mycroft
83 1.16 lukem static u_int st_hash(const char *, size_t, int);
84 1.16 lukem static int uidtb_start(void);
85 1.16 lukem static int gidtb_start(void);
86 1.16 lukem static int usrtb_start(void);
87 1.16 lukem static int grptb_start(void);
88 1.10 mycroft
89 1.10 mycroft static u_int
90 1.16 lukem st_hash(const char *name, size_t len, int tabsz)
91 1.10 mycroft {
92 1.10 mycroft u_int key = 0;
93 1.10 mycroft
94 1.13 lukem _DIAGASSERT(name != NULL);
95 1.13 lukem
96 1.10 mycroft while (len--) {
97 1.10 mycroft key += *name++;
98 1.10 mycroft key = (key << 8) | (key >> 24);
99 1.10 mycroft }
100 1.10 mycroft
101 1.10 mycroft return (key % tabsz);
102 1.10 mycroft }
103 1.10 mycroft
104 1.10 mycroft /*
105 1.10 mycroft * uidtb_start
106 1.10 mycroft * creates an an empty uidtb
107 1.10 mycroft * Return:
108 1.10 mycroft * 0 if ok, -1 otherwise
109 1.10 mycroft */
110 1.10 mycroft
111 1.10 mycroft static int
112 1.10 mycroft uidtb_start(void)
113 1.10 mycroft {
114 1.10 mycroft static int fail = 0;
115 1.10 mycroft
116 1.10 mycroft if (uidtb != NULL)
117 1.10 mycroft return (0);
118 1.10 mycroft if (fail)
119 1.10 mycroft return (-1);
120 1.10 mycroft if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
121 1.10 mycroft ++fail;
122 1.10 mycroft return (-1);
123 1.10 mycroft }
124 1.10 mycroft return (0);
125 1.10 mycroft }
126 1.10 mycroft
127 1.10 mycroft /*
128 1.10 mycroft * gidtb_start
129 1.10 mycroft * creates an an empty gidtb
130 1.10 mycroft * Return:
131 1.10 mycroft * 0 if ok, -1 otherwise
132 1.10 mycroft */
133 1.1 cgd
134 1.10 mycroft int
135 1.10 mycroft gidtb_start(void)
136 1.10 mycroft {
137 1.10 mycroft static int fail = 0;
138 1.10 mycroft
139 1.10 mycroft if (gidtb != NULL)
140 1.10 mycroft return (0);
141 1.10 mycroft if (fail)
142 1.10 mycroft return (-1);
143 1.10 mycroft if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
144 1.10 mycroft ++fail;
145 1.10 mycroft return (-1);
146 1.10 mycroft }
147 1.10 mycroft return (0);
148 1.10 mycroft }
149 1.10 mycroft
150 1.10 mycroft /*
151 1.10 mycroft * usrtb_start
152 1.10 mycroft * creates an an empty usrtb
153 1.10 mycroft * Return:
154 1.10 mycroft * 0 if ok, -1 otherwise
155 1.10 mycroft */
156 1.10 mycroft
157 1.10 mycroft int
158 1.10 mycroft usrtb_start(void)
159 1.10 mycroft {
160 1.10 mycroft static int fail = 0;
161 1.10 mycroft
162 1.10 mycroft if (usrtb != NULL)
163 1.10 mycroft return (0);
164 1.10 mycroft if (fail)
165 1.10 mycroft return (-1);
166 1.10 mycroft if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
167 1.10 mycroft ++fail;
168 1.10 mycroft return (-1);
169 1.10 mycroft }
170 1.10 mycroft return (0);
171 1.10 mycroft }
172 1.10 mycroft
173 1.10 mycroft /*
174 1.10 mycroft * grptb_start
175 1.10 mycroft * creates an an empty grptb
176 1.10 mycroft * Return:
177 1.10 mycroft * 0 if ok, -1 otherwise
178 1.10 mycroft */
179 1.10 mycroft
180 1.10 mycroft int
181 1.10 mycroft grptb_start(void)
182 1.10 mycroft {
183 1.10 mycroft static int fail = 0;
184 1.10 mycroft
185 1.10 mycroft if (grptb != NULL)
186 1.10 mycroft return (0);
187 1.10 mycroft if (fail)
188 1.10 mycroft return (-1);
189 1.10 mycroft if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
190 1.10 mycroft ++fail;
191 1.10 mycroft return (-1);
192 1.10 mycroft }
193 1.10 mycroft return (0);
194 1.10 mycroft }
195 1.10 mycroft
196 1.10 mycroft /*
197 1.11 mycroft * user_from_uid()
198 1.16 lukem * caches the name (if any) for the uid. If noname clear, we always
199 1.16 lukem * return the the stored name (if valid or invalid match).
200 1.16 lukem * We use a simple hash table.
201 1.10 mycroft * Return
202 1.10 mycroft * Pointer to stored name (or a empty string)
203 1.10 mycroft */
204 1.10 mycroft
205 1.10 mycroft const char *
206 1.10 mycroft user_from_uid(uid_t uid, int noname)
207 1.1 cgd {
208 1.9 perry struct passwd *pw;
209 1.10 mycroft UIDC *ptr, **pptr;
210 1.1 cgd
211 1.10 mycroft if ((uidtb == NULL) && (uidtb_start() < 0))
212 1.10 mycroft return (NULL);
213 1.10 mycroft
214 1.10 mycroft /*
215 1.10 mycroft * see if we have this uid cached
216 1.10 mycroft */
217 1.10 mycroft pptr = uidtb + (uid % UID_SZ);
218 1.10 mycroft ptr = *pptr;
219 1.10 mycroft
220 1.10 mycroft if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
221 1.10 mycroft /*
222 1.10 mycroft * have an entry for this uid
223 1.10 mycroft */
224 1.10 mycroft if (!noname || (ptr->valid == VALID))
225 1.10 mycroft return (ptr->name);
226 1.10 mycroft return (NULL);
227 1.10 mycroft }
228 1.10 mycroft
229 1.10 mycroft /*
230 1.10 mycroft * No entry for this uid, we will add it
231 1.10 mycroft */
232 1.10 mycroft if (!pwopn) {
233 1.10 mycroft setpassent(1);
234 1.10 mycroft ++pwopn;
235 1.1 cgd }
236 1.10 mycroft
237 1.10 mycroft if (ptr == NULL)
238 1.12 mycroft *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
239 1.10 mycroft
240 1.10 mycroft if ((pw = getpwuid(uid)) == NULL) {
241 1.10 mycroft /*
242 1.10 mycroft * no match for this uid in the local password file
243 1.10 mycroft * a string that is the uid in numberic format
244 1.10 mycroft */
245 1.10 mycroft if (ptr == NULL)
246 1.10 mycroft return (NULL);
247 1.10 mycroft ptr->uid = uid;
248 1.10 mycroft (void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid);
249 1.10 mycroft ptr->valid = INVALID;
250 1.10 mycroft if (noname)
251 1.10 mycroft return (NULL);
252 1.10 mycroft } else {
253 1.10 mycroft /*
254 1.10 mycroft * there is an entry for this uid in the password file
255 1.10 mycroft */
256 1.10 mycroft if (ptr == NULL)
257 1.10 mycroft return (pw->pw_name);
258 1.10 mycroft ptr->uid = uid;
259 1.10 mycroft (void)strncpy(ptr->name, pw->pw_name, UNMLEN);
260 1.10 mycroft ptr->name[UNMLEN-1] = '\0';
261 1.10 mycroft ptr->valid = VALID;
262 1.10 mycroft }
263 1.10 mycroft return (ptr->name);
264 1.1 cgd }
265 1.1 cgd
266 1.10 mycroft /*
267 1.10 mycroft * group_from_gid()
268 1.16 lukem * caches the name (if any) for the gid. If noname clear, we always
269 1.16 lukem * return the the stored name (if valid or invalid match).
270 1.16 lukem * We use a simple hash table.
271 1.10 mycroft * Return
272 1.10 mycroft * Pointer to stored name (or a empty string)
273 1.10 mycroft */
274 1.10 mycroft
275 1.10 mycroft const char *
276 1.10 mycroft group_from_gid(gid_t gid, int noname)
277 1.10 mycroft {
278 1.10 mycroft struct group *gr;
279 1.10 mycroft GIDC *ptr, **pptr;
280 1.10 mycroft
281 1.10 mycroft if ((gidtb == NULL) && (gidtb_start() < 0))
282 1.10 mycroft return (NULL);
283 1.10 mycroft
284 1.10 mycroft /*
285 1.10 mycroft * see if we have this gid cached
286 1.10 mycroft */
287 1.10 mycroft pptr = gidtb + (gid % GID_SZ);
288 1.10 mycroft ptr = *pptr;
289 1.10 mycroft
290 1.10 mycroft if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
291 1.10 mycroft /*
292 1.10 mycroft * have an entry for this gid
293 1.10 mycroft */
294 1.10 mycroft if (!noname || (ptr->valid == VALID))
295 1.10 mycroft return (ptr->name);
296 1.10 mycroft return (NULL);
297 1.10 mycroft }
298 1.10 mycroft
299 1.10 mycroft /*
300 1.10 mycroft * No entry for this gid, we will add it
301 1.10 mycroft */
302 1.10 mycroft if (!gropn) {
303 1.10 mycroft setgroupent(1);
304 1.10 mycroft ++gropn;
305 1.10 mycroft }
306 1.10 mycroft
307 1.10 mycroft if (ptr == NULL)
308 1.12 mycroft *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
309 1.10 mycroft
310 1.10 mycroft if ((gr = getgrgid(gid)) == NULL) {
311 1.10 mycroft /*
312 1.10 mycroft * no match for this gid in the local group file, put in
313 1.10 mycroft * a string that is the gid in numberic format
314 1.10 mycroft */
315 1.10 mycroft if (ptr == NULL)
316 1.10 mycroft return (NULL);
317 1.10 mycroft ptr->gid = gid;
318 1.10 mycroft (void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid);
319 1.10 mycroft ptr->valid = INVALID;
320 1.10 mycroft if (noname)
321 1.10 mycroft return (NULL);
322 1.10 mycroft } else {
323 1.10 mycroft /*
324 1.10 mycroft * there is an entry for this group in the group file
325 1.10 mycroft */
326 1.10 mycroft if (ptr == NULL)
327 1.10 mycroft return (gr->gr_name);
328 1.10 mycroft ptr->gid = gid;
329 1.10 mycroft (void)strncpy(ptr->name, gr->gr_name, GNMLEN);
330 1.10 mycroft ptr->name[GNMLEN-1] = '\0';
331 1.10 mycroft ptr->valid = VALID;
332 1.10 mycroft }
333 1.10 mycroft return (ptr->name);
334 1.10 mycroft }
335 1.10 mycroft
336 1.10 mycroft /*
337 1.10 mycroft * uid_from_user()
338 1.10 mycroft * caches the uid for a given user name. We use a simple hash table.
339 1.10 mycroft * Return
340 1.10 mycroft * the uid (if any) for a user name, or a -1 if no match can be found
341 1.10 mycroft */
342 1.10 mycroft
343 1.10 mycroft int
344 1.10 mycroft uid_from_user(const char *name, uid_t *uid)
345 1.10 mycroft {
346 1.10 mycroft struct passwd *pw;
347 1.10 mycroft UIDC *ptr, **pptr;
348 1.10 mycroft size_t namelen;
349 1.10 mycroft
350 1.10 mycroft /*
351 1.10 mycroft * return -1 for mangled names
352 1.10 mycroft */
353 1.13 lukem if (name == NULL || ((namelen = strlen(name)) == 0))
354 1.10 mycroft return (-1);
355 1.10 mycroft if ((usrtb == NULL) && (usrtb_start() < 0))
356 1.10 mycroft return (-1);
357 1.10 mycroft
358 1.10 mycroft /*
359 1.10 mycroft * look up in hash table, if found and valid return the uid,
360 1.10 mycroft * if found and invalid, return a -1
361 1.10 mycroft */
362 1.10 mycroft pptr = usrtb + st_hash(name, namelen, UNM_SZ);
363 1.10 mycroft ptr = *pptr;
364 1.10 mycroft
365 1.10 mycroft if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
366 1.10 mycroft if (ptr->valid == INVALID)
367 1.10 mycroft return (-1);
368 1.10 mycroft *uid = ptr->uid;
369 1.10 mycroft return (0);
370 1.10 mycroft }
371 1.10 mycroft
372 1.10 mycroft if (!pwopn) {
373 1.10 mycroft setpassent(1);
374 1.10 mycroft ++pwopn;
375 1.10 mycroft }
376 1.10 mycroft
377 1.10 mycroft if (ptr == NULL)
378 1.12 mycroft *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
379 1.10 mycroft
380 1.10 mycroft /*
381 1.10 mycroft * no match, look it up, if no match store it as an invalid entry,
382 1.10 mycroft * or store the matching uid
383 1.10 mycroft */
384 1.10 mycroft if (ptr == NULL) {
385 1.10 mycroft if ((pw = getpwnam(name)) == NULL)
386 1.10 mycroft return (-1);
387 1.10 mycroft *uid = pw->pw_uid;
388 1.10 mycroft return (0);
389 1.10 mycroft }
390 1.10 mycroft (void)strncpy(ptr->name, name, UNMLEN);
391 1.10 mycroft ptr->name[UNMLEN-1] = '\0';
392 1.10 mycroft if ((pw = getpwnam(name)) == NULL) {
393 1.10 mycroft ptr->valid = INVALID;
394 1.10 mycroft return (-1);
395 1.10 mycroft }
396 1.10 mycroft ptr->valid = VALID;
397 1.10 mycroft *uid = ptr->uid = pw->pw_uid;
398 1.10 mycroft return (0);
399 1.10 mycroft }
400 1.10 mycroft
401 1.10 mycroft /*
402 1.10 mycroft * gid_from_group()
403 1.10 mycroft * caches the gid for a given group name. We use a simple hash table.
404 1.10 mycroft * Return
405 1.10 mycroft * the gid (if any) for a group name, or a -1 if no match can be found
406 1.10 mycroft */
407 1.10 mycroft
408 1.10 mycroft int
409 1.10 mycroft gid_from_group(const char *name, gid_t *gid)
410 1.1 cgd {
411 1.4 cgd struct group *gr;
412 1.10 mycroft GIDC *ptr, **pptr;
413 1.10 mycroft size_t namelen;
414 1.10 mycroft
415 1.10 mycroft /*
416 1.10 mycroft * return -1 for mangled names
417 1.10 mycroft */
418 1.13 lukem if (name == NULL || ((namelen = strlen(name)) == 0))
419 1.10 mycroft return (-1);
420 1.10 mycroft if ((grptb == NULL) && (grptb_start() < 0))
421 1.10 mycroft return (-1);
422 1.10 mycroft
423 1.10 mycroft /*
424 1.10 mycroft * look up in hash table, if found and valid return the uid,
425 1.10 mycroft * if found and invalid, return a -1
426 1.10 mycroft */
427 1.10 mycroft pptr = grptb + st_hash(name, namelen, GID_SZ);
428 1.10 mycroft ptr = *pptr;
429 1.10 mycroft
430 1.10 mycroft if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
431 1.10 mycroft if (ptr->valid == INVALID)
432 1.10 mycroft return (-1);
433 1.10 mycroft *gid = ptr->gid;
434 1.10 mycroft return (0);
435 1.10 mycroft }
436 1.10 mycroft
437 1.10 mycroft if (!gropn) {
438 1.10 mycroft setgroupent(1);
439 1.10 mycroft ++gropn;
440 1.10 mycroft }
441 1.10 mycroft
442 1.10 mycroft if (ptr == NULL)
443 1.12 mycroft *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
444 1.10 mycroft
445 1.10 mycroft /*
446 1.10 mycroft * no match, look it up, if no match store it as an invalid entry,
447 1.10 mycroft * or store the matching gid
448 1.10 mycroft */
449 1.10 mycroft if (ptr == NULL) {
450 1.10 mycroft if ((gr = getgrnam(name)) == NULL)
451 1.10 mycroft return (-1);
452 1.10 mycroft *gid = gr->gr_gid;
453 1.10 mycroft return (0);
454 1.10 mycroft }
455 1.1 cgd
456 1.10 mycroft (void)strncpy(ptr->name, name, GNMLEN);
457 1.10 mycroft ptr->name[GNMLEN-1] = '\0';
458 1.10 mycroft if ((gr = getgrnam(name)) == NULL) {
459 1.10 mycroft ptr->valid = INVALID;
460 1.10 mycroft return (-1);
461 1.1 cgd }
462 1.10 mycroft ptr->valid = VALID;
463 1.10 mycroft *gid = ptr->gid = gr->gr_gid;
464 1.10 mycroft return (0);
465 1.1 cgd }
466