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