cache.c revision 21673
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 *	$FreeBSD: head/bin/pax/cache.c 21673 1997-01-14 07:20:47Z jkh $
38 */
39
40#ifndef lint
41static char const sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <sys/time.h>
46#include <sys/stat.h>
47#include <sys/param.h>
48#include <string.h>
49#include <stdio.h>
50#include <pwd.h>
51#include <grp.h>
52#include <unistd.h>
53#include <stdlib.h>
54#include "pax.h"
55#include "cache.h"
56#include "extern.h"
57
58/*
59 * routines that control user, group, uid and gid caches (for the archive
60 * member print routine).
61 * IMPORTANT:
62 * these routines cache BOTH hits and misses, a major performance improvement
63 */
64
65static	int pwopn = 0;		/* is password file open */
66static	int gropn = 0;		/* is group file open */
67static UIDC **uidtb = NULL;	/* uid to name cache */
68static GIDC **gidtb = NULL;	/* gid to name cache */
69static UIDC **usrtb = NULL;	/* user name to uid cache */
70static GIDC **grptb = NULL;	/* group name to gid cache */
71
72/*
73 * uidtb_start
74 *	creates an an empty uidtb
75 * Return:
76 *	0 if ok, -1 otherwise
77 */
78
79#if __STDC__
80int
81uidtb_start(void)
82#else
83int
84uidtb_start()
85#endif
86{
87	static int fail = 0;
88
89	if (uidtb != NULL)
90		return(0);
91	if (fail)
92		return(-1);
93	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
94		++fail;
95		warn(1, "Unable to allocate memory for user id cache table");
96		return(-1);
97	}
98	return(0);
99}
100
101/*
102 * gidtb_start
103 *	creates an an empty gidtb
104 * Return:
105 *	0 if ok, -1 otherwise
106 */
107
108#if __STDC__
109int
110gidtb_start(void)
111#else
112int
113gidtb_start()
114#endif
115{
116	static int fail = 0;
117
118	if (gidtb != NULL)
119		return(0);
120	if (fail)
121		return(-1);
122	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
123		++fail;
124		warn(1, "Unable to allocate memory for group id cache table");
125		return(-1);
126	}
127	return(0);
128}
129
130/*
131 * usrtb_start
132 *	creates an an empty usrtb
133 * Return:
134 *	0 if ok, -1 otherwise
135 */
136
137#if __STDC__
138int
139usrtb_start(void)
140#else
141int
142usrtb_start()
143#endif
144{
145	static int fail = 0;
146
147	if (usrtb != NULL)
148		return(0);
149	if (fail)
150		return(-1);
151	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
152		++fail;
153		warn(1, "Unable to allocate memory for user name cache table");
154		return(-1);
155	}
156	return(0);
157}
158
159/*
160 * grptb_start
161 *	creates an an empty grptb
162 * Return:
163 *	0 if ok, -1 otherwise
164 */
165
166#if __STDC__
167int
168grptb_start(void)
169#else
170int
171grptb_start()
172#endif
173{
174	static int fail = 0;
175
176	if (grptb != NULL)
177		return(0);
178	if (fail)
179		return(-1);
180	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
181		++fail;
182		warn(1,"Unable to allocate memory for group name cache table");
183		return(-1);
184	}
185	return(0);
186}
187
188/*
189 * name_uid()
190 *	caches the name (if any) for the uid. If frc set, we always return the
191 *	the stored name (if valid or invalid match). We use a simple hash table.
192 * Return
193 *	Pointer to stored name (or a empty string)
194 */
195
196#if __STDC__
197char *
198name_uid(uid_t uid, int frc)
199#else
200char *
201name_uid(uid, frc)
202	uid_t uid;
203	int frc;
204#endif
205{
206	register struct passwd *pw;
207	register UIDC *ptr;
208
209	if ((uidtb == NULL) && (uidtb_start() < 0))
210		return("");
211
212	/*
213	 * see if we have this uid cached
214	 */
215	ptr = uidtb[uid % UID_SZ];
216	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
217		/*
218		 * have an entry for this uid
219		 */
220		if (frc || (ptr->valid == VALID))
221			return(ptr->name);
222		return("");
223	}
224
225	/*
226	 * No entry for this uid, we will add it
227	 */
228	if (!pwopn) {
229		setpassent(1);
230		++pwopn;
231	}
232	if (ptr == NULL)
233		ptr = (UIDC *)malloc(sizeof(UIDC));
234
235	if ((pw = getpwuid(uid)) == NULL) {
236		/*
237		 * no match for this uid in the local password file
238		 * a string that is the uid in numberic format
239		 */
240		if (ptr == NULL)
241			return("");
242		ptr->uid = uid;
243		ptr->valid = INVALID;
244#		ifdef NET2_STAT
245		(void)sprintf(ptr->name, "%u", uid);
246#		else
247		(void)sprintf(ptr->name, "%lu", (u_long)uid);
248#		endif
249		if (frc == 0)
250			return("");
251	} else {
252		/*
253		 * there is an entry for this uid in the password file
254		 */
255		if (ptr == NULL)
256			return(pw->pw_name);
257		ptr->uid = uid;
258		(void)strncpy(ptr->name, pw->pw_name, UNMLEN);
259		ptr->name[UNMLEN-1] = '\0';
260		ptr->valid = VALID;
261	}
262	return(ptr->name);
263}
264
265/*
266 * name_gid()
267 *	caches the name (if any) for the gid. If frc set, we always return the
268 *	the stored name (if valid or invalid match). We use a simple hash table.
269 * Return
270 *	Pointer to stored name (or a empty string)
271 */
272
273#if __STDC__
274char *
275name_gid(gid_t gid, int frc)
276#else
277char *
278name_gid(gid, frc)
279	gid_t gid;
280	int frc;
281#endif
282{
283	register struct group *gr;
284	register GIDC *ptr;
285
286	if ((gidtb == NULL) && (gidtb_start() < 0))
287		return("");
288
289	/*
290	 * see if we have this gid cached
291	 */
292	ptr = gidtb[gid % GID_SZ];
293	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
294		/*
295		 * have an entry for this gid
296		 */
297		if (frc || (ptr->valid == VALID))
298			return(ptr->name);
299		return("");
300	}
301
302	/*
303	 * No entry for this gid, we will add it
304	 */
305	if (!gropn) {
306		setgroupent(1);
307		++gropn;
308	}
309	if (ptr == NULL)
310		ptr = (GIDC *)malloc(sizeof(GIDC));
311
312	if ((gr = getgrgid(gid)) == NULL) {
313		/*
314		 * no match for this gid in the local group file, put in
315		 * a string that is the gid in numberic format
316		 */
317		if (ptr == NULL)
318			return("");
319		ptr->gid = gid;
320		ptr->valid = INVALID;
321#		ifdef NET2_STAT
322		(void)sprintf(ptr->name, "%u", gid);
323#		else
324		(void)sprintf(ptr->name, "%lu", (u_long)gid);
325#		endif
326		if (frc == 0)
327			return("");
328	} else {
329		/*
330		 * there is an entry for this group in the group file
331		 */
332		if (ptr == NULL)
333			return(gr->gr_name);
334		ptr->gid = gid;
335		(void)strncpy(ptr->name, gr->gr_name, GNMLEN);
336		ptr->name[GNMLEN-1] = '\0';
337		ptr->valid = VALID;
338	}
339	return(ptr->name);
340}
341
342/*
343 * uid_name()
344 *	caches the uid for a given user name. We use a simple hash table.
345 * Return
346 *	the uid (if any) for a user name, or a -1 if no match can be found
347 */
348
349#if __STDC__
350int
351uid_name(char *name, uid_t *uid)
352#else
353int
354uid_name(name, uid)
355	char *name;
356	uid_t *uid;
357#endif
358{
359	register struct passwd *pw;
360	register UIDC *ptr;
361	register int namelen;
362
363	/*
364	 * return -1 for mangled names
365	 */
366	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
367		return(-1);
368	if ((usrtb == NULL) && (usrtb_start() < 0))
369		return(-1);
370
371	/*
372	 * look up in hash table, if found and valid return the uid,
373	 * if found and invalid, return a -1
374	 */
375	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
376	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
377		if (ptr->valid == INVALID)
378			return(-1);
379		*uid = ptr->uid;
380		return(0);
381	}
382
383	if (!pwopn) {
384		setpassent(1);
385		++pwopn;
386	}
387
388	if (ptr == NULL)
389		ptr = (UIDC *)malloc(sizeof(UIDC));
390
391	/*
392	 * no match, look it up, if no match store it as an invalid entry,
393	 * or store the matching uid
394	 */
395	if (ptr == NULL) {
396		if ((pw = getpwnam(name)) == NULL)
397			return(-1);
398		*uid = pw->pw_uid;
399		return(0);
400	}
401	(void)strncpy(ptr->name, name, UNMLEN);
402	ptr->name[UNMLEN-1] = '\0';
403	if ((pw = getpwnam(name)) == NULL) {
404		ptr->valid = INVALID;
405		return(-1);
406	}
407	ptr->valid = VALID;
408	*uid = ptr->uid = pw->pw_uid;
409	return(0);
410}
411
412/*
413 * gid_name()
414 *	caches the gid for a given group name. We use a simple hash table.
415 * Return
416 *	the gid (if any) for a group name, or a -1 if no match can be found
417 */
418
419#if __STDC__
420int
421gid_name(char *name, gid_t *gid)
422#else
423int
424gid_name(name, gid)
425	char *name;
426	gid_t *gid;
427#endif
428{
429	register struct group *gr;
430	register GIDC *ptr;
431	register int namelen;
432
433	/*
434	 * return -1 for mangled names
435	 */
436	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
437		return(-1);
438	if ((grptb == NULL) && (grptb_start() < 0))
439		return(-1);
440
441	/*
442	 * look up in hash table, if found and valid return the uid,
443	 * if found and invalid, return a -1
444	 */
445	ptr = grptb[st_hash(name, namelen, GID_SZ)];
446	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
447		if (ptr->valid == INVALID)
448			return(-1);
449		*gid = ptr->gid;
450		return(0);
451	}
452
453	if (!gropn) {
454		setgroupent(1);
455		++gropn;
456	}
457	if (ptr == NULL)
458		ptr = (GIDC *)malloc(sizeof(GIDC));
459
460	/*
461	 * no match, look it up, if no match store it as an invalid entry,
462	 * or store the matching gid
463	 */
464	if (ptr == NULL) {
465		if ((gr = getgrnam(name)) == NULL)
466			return(-1);
467		*gid = gr->gr_gid;
468		return(0);
469	}
470
471	(void)strncpy(ptr->name, name, GNMLEN);
472	ptr->name[GNMLEN-1] = '\0';
473	if ((gr = getgrnam(name)) == NULL) {
474		ptr->valid = INVALID;
475		return(-1);
476	}
477	ptr->valid = VALID;
478	*gid = ptr->gid = gr->gr_gid;
479	return(0);
480}
481