cache.c revision 127055
121308Sache/*-
221308Sache * Copyright (c) 1992 Keith Muller.
321308Sache * Copyright (c) 1992, 1993
421308Sache *	The Regents of the University of California.  All rights reserved.
521308Sache *
621308Sache * This code is derived from software contributed to Berkeley by
7157184Sache * Keith Muller of the University of California, San Diego.
821308Sache *
921308Sache * Redistribution and use in source and binary forms, with or without
1021308Sache * modification, are permitted provided that the following conditions
1121308Sache * are met:
1221308Sache * 1. Redistributions of source code must retain the above copyright
1321308Sache *    notice, this list of conditions and the following disclaimer.
1421308Sache * 2. Redistributions in binary form must reproduce the above copyright
1558310Sache *    notice, this list of conditions and the following disclaimer in the
1621308Sache *    documentation and/or other materials provided with the distribution.
1721308Sache * 3. All advertising materials mentioning features or use of this software
1821308Sache *    must display the following acknowledgement:
1921308Sache *	This product includes software developed by the University of
2021308Sache *	California, Berkeley and its contributors.
2121308Sache * 4. Neither the name of the University nor the names of its contributors
2221308Sache *    may be used to endorse or promote products derived from this software
2321308Sache *    without specific prior written permission.
2421308Sache *
2521308Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2658310Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2721308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2821308Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2921308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3021308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3121308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3221308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3326497Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3426497Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3521308Sache * SUCH DAMAGE.
3621308Sache */
3721308Sache
3821308Sache#ifndef lint
3921308Sache#if 0
4021308Sachestatic char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
4126497Sache#endif
4226497Sache#endif /* not lint */
4326497Sache#include <sys/cdefs.h>
4426497Sache__FBSDID("$FreeBSD: head/bin/pax/cache.c 127055 2004-03-16 08:33:33Z cperciva $");
4526497Sache
4621308Sache#include <sys/types.h>
4721308Sache#include <sys/stat.h>
48119610Sache#include <string.h>
49119610Sache#include <stdio.h>
5021308Sache#include <pwd.h>
5121308Sache#include <grp.h>
5221308Sache#include <unistd.h>
5358310Sache#include <stdlib.h>
5458310Sache#include "pax.h"
5558310Sache#include "cache.h"
5647558Sache#include "extern.h"
57119610Sache
5847558Sache/*
59157184Sache * routines that control user, group, uid and gid caches (for the archive
60157184Sache * member print routine).
6121308Sache * IMPORTANT:
6275406Sache * these routines cache BOTH hits and misses, a major performance improvement
6321308Sache */
64119610Sache
6521308Sachestatic	int pwopn = 0;		/* is password file open */
66157184Sachestatic	int gropn = 0;		/* is group file open */
67157184Sachestatic UIDC **uidtb = NULL;	/* uid to name cache */
68157184Sachestatic GIDC **gidtb = NULL;	/* gid to name cache */
69157184Sachestatic UIDC **usrtb = NULL;	/* user name to uid cache */
7021308Sachestatic GIDC **grptb = NULL;	/* group name to gid cache */
71165670Sache
72165670Sache/*
7321308Sache * uidtb_start
74119610Sache *	creates an an empty uidtb
75119610Sache * Return:
76119610Sache *	0 if ok, -1 otherwise
7775406Sache */
78119610Sache
79119610Sacheint
80157184Sacheuidtb_start(void)
81157184Sache{
82157184Sache	static int fail = 0;
83157184Sache
84157184Sache	if (uidtb != NULL)
85157184Sache		return(0);
86157184Sache	if (fail)
87157184Sache		return(-1);
88157184Sache	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
89157184Sache		++fail;
90157184Sache		paxwarn(1, "Unable to allocate memory for user id cache table");
91157184Sache		return(-1);
92157184Sache	}
93157184Sache	return(0);
94157184Sache}
95157184Sache
96157184Sache/*
97157184Sache * gidtb_start
98157184Sache *	creates an an empty gidtb
99157184Sache * Return:
100157184Sache *	0 if ok, -1 otherwise
101157184Sache */
102157184Sache
103157184Sacheint
104157184Sachegidtb_start(void)
105157184Sache{
106157184Sache	static int fail = 0;
107157184Sache
108157184Sache	if (gidtb != NULL)
109157184Sache		return(0);
110157184Sache	if (fail)
111157184Sache		return(-1);
112157184Sache	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
113157184Sache		++fail;
114157184Sache		paxwarn(1, "Unable to allocate memory for group id cache table");
115157184Sache		return(-1);
116157184Sache	}
117157184Sache	return(0);
118157184Sache}
119157184Sache
120157184Sache/*
121157184Sache * usrtb_start
122157184Sache *	creates an an empty usrtb
123157184Sache * Return:
124157184Sache *	0 if ok, -1 otherwise
125157184Sache */
126157184Sache
127157184Sacheint
128157184Sacheusrtb_start(void)
129157184Sache{
130157184Sache	static int fail = 0;
13121308Sache
13221308Sache	if (usrtb != NULL)
13321308Sache		return(0);
13421308Sache	if (fail)
13521308Sache		return(-1);
13621308Sache	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
13721308Sache		++fail;
13821308Sache		paxwarn(1, "Unable to allocate memory for user name cache table");
13921308Sache		return(-1);
14021308Sache	}
14121308Sache	return(0);
14221308Sache}
14321308Sache
14421308Sache/*
14521308Sache * grptb_start
14621308Sache *	creates an an empty grptb
14721308Sache * Return:
14821308Sache *	0 if ok, -1 otherwise
14921308Sache */
15021308Sache
151157184Sacheint
15221308Sachegrptb_start(void)
15321308Sache{
15421308Sache	static int fail = 0;
15521308Sache
15621308Sache	if (grptb != NULL)
15721308Sache		return(0);
15821308Sache	if (fail)
15921308Sache		return(-1);
16021308Sache	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
16121308Sache		++fail;
16221308Sache		paxwarn(1,"Unable to allocate memory for group name cache table");
16321308Sache		return(-1);
164119610Sache	}
16521308Sache	return(0);
16621308Sache}
16721308Sache
16821308Sache/*
16921308Sache * name_uid()
17021308Sache *	caches the name (if any) for the uid. If frc set, we always return the
17121308Sache *	the stored name (if valid or invalid match). We use a simple hash table.
17221308Sache * Return
17321308Sache *	Pointer to stored name (or an empty string).
17421308Sache */
17521308Sache
17621308Sacheconst char *
17721308Sachename_uid(uid_t uid, int frc)
17821308Sache{
17921308Sache	struct passwd *pw;
18021308Sache	UIDC *ptr;
18121308Sache
18221308Sache	if ((uidtb == NULL) && (uidtb_start() < 0))
18321308Sache		return("");
18421308Sache
18521308Sache	/*
18621308Sache	 * see if we have this uid cached
18721308Sache	 */
18821308Sache	ptr = uidtb[uid % UID_SZ];
18921308Sache	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
19021308Sache		/*
19121308Sache		 * have an entry for this uid
19221308Sache		 */
19321308Sache		if (frc || (ptr->valid == VALID))
194119610Sache			return(ptr->name);
19521308Sache		return("");
19621308Sache	}
19721308Sache
19821308Sache	/*
199157184Sache	 * No entry for this uid, we will add it
200157184Sache	 */
201157184Sache	if (!pwopn) {
20221308Sache		setpassent(1);
203157184Sache		++pwopn;
204157184Sache	}
20521308Sache	if (ptr == NULL)
20621308Sache		ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC));
207157184Sache
208157184Sache	if ((pw = getpwuid(uid)) == NULL) {
209157184Sache		/*
21021308Sache		 * no match for this uid in the local password file
211157184Sache		 * a string that is the uid in numeric format
21275406Sache		 */
21347558Sache		if (ptr == NULL)
21421308Sache			return("");
215157184Sache		ptr->uid = uid;
21675406Sache		ptr->valid = INVALID;
21721308Sache#		ifdef NET2_STAT
21821308Sache		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
21921308Sache#		else
22021308Sache		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
22121308Sache			       (unsigned long)uid);
22221308Sache#		endif
223157184Sache		if (frc == 0)
224157184Sache			return("");
225157184Sache	} else {
22621308Sache		/*
22775406Sache		 * there is an entry for this uid in the password file
228157184Sache		 */
22921308Sache		if (ptr == NULL)
23021308Sache			return(pw->pw_name);
23121308Sache		ptr->uid = uid;
232157184Sache		(void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
233157184Sache		ptr->name[UNMLEN-1] = '\0';
234157184Sache		ptr->valid = VALID;
23521308Sache	}
23621308Sache	return(ptr->name);
237157184Sache}
23821308Sache
23921308Sache/*
240157184Sache * name_gid()
24121308Sache *	caches the name (if any) for the gid. If frc set, we always return the
24247558Sache *	the stored name (if valid or invalid match). We use a simple hash table.
24321308Sache * Return
24421308Sache *	Pointer to stored name (or an empty string).
245157184Sache */
246157184Sache
24721308Sacheconst char *
24821308Sachename_gid(gid_t gid, int frc)
249157184Sache{
25021308Sache	struct group *gr;
251157184Sache	GIDC *ptr;
252157184Sache
253157184Sache	if ((gidtb == NULL) && (gidtb_start() < 0))
25421308Sache		return("");
255157184Sache
25621308Sache	/*
257157184Sache	 * see if we have this gid cached
258157184Sache	 */
259157184Sache	ptr = gidtb[gid % GID_SZ];
260157184Sache	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
261157184Sache		/*
262157184Sache		 * have an entry for this gid
263157184Sache		 */
264157184Sache		if (frc || (ptr->valid == VALID))
265157184Sache			return(ptr->name);
266157184Sache		return("");
267157184Sache	}
268157184Sache
269157184Sache	/*
270157184Sache	 * No entry for this gid, we will add it
271157184Sache	 */
272157184Sache	if (!gropn) {
273157184Sache		setgroupent(1);
274157184Sache		++gropn;
275157184Sache	}
276157184Sache	if (ptr == NULL)
277157184Sache		ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC));
278157184Sache
279157184Sache	if ((gr = getgrgid(gid)) == NULL) {
280157184Sache		/*
281157184Sache		 * no match for this gid in the local group file, put in
282157184Sache		 * a string that is the gid in numeric format
283157184Sache		 */
28421308Sache		if (ptr == NULL)
285157184Sache			return("");
286157184Sache		ptr->gid = gid;
287157184Sache		ptr->valid = INVALID;
288157184Sache#		ifdef NET2_STAT
289157184Sache		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
290157184Sache#		else
29121308Sache		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
292157184Sache			       (unsigned long)gid);
293157184Sache#		endif
294157184Sache		if (frc == 0)
29521308Sache			return("");
296157184Sache	} else {
297157184Sache		/*
298157184Sache		 * there is an entry for this group in the group file
299157184Sache		 */
300157184Sache		if (ptr == NULL)
301157184Sache			return(gr->gr_name);
302157184Sache		ptr->gid = gid;
303157184Sache		(void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
304157184Sache		ptr->name[GNMLEN-1] = '\0';
305157184Sache		ptr->valid = VALID;
306157184Sache	}
307157184Sache	return(ptr->name);
308157184Sache}
309157184Sache
310119610Sache/*
311157184Sache * uid_name()
312157184Sache *	caches the uid for a given user name. We use a simple hash table.
313119610Sache * Return
314119610Sache *	the uid (if any) for a user name, or a -1 if no match can be found
315157184Sache */
316157184Sache
31721308Sacheint
318157184Sacheuid_name(char *name, uid_t *uid)
319157184Sache{
320157184Sache	struct passwd *pw;
321157184Sache	UIDC *ptr;
322157184Sache	int namelen;
323157184Sache
324157184Sache	/*
325157184Sache	 * return -1 for mangled names
326157184Sache	 */
327157184Sache	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
32821308Sache		return(-1);
329157184Sache	if ((usrtb == NULL) && (usrtb_start() < 0))
330173403Sache		return(-1);
331173403Sache
332173403Sache	/*
333173403Sache	 * look up in hash table, if found and valid return the uid,
334173403Sache	 * if found and invalid, return a -1
335173403Sache	 */
336173403Sache	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
337173403Sache	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
338173403Sache		if (ptr->valid == INVALID)
339157184Sache			return(-1);
340157184Sache		*uid = ptr->uid;
341157184Sache		return(0);
34221308Sache	}
343157184Sache
344157184Sache	if (!pwopn) {
345157184Sache		setpassent(1);
346157184Sache		++pwopn;
347157184Sache	}
348157184Sache
349157184Sache	if (ptr == NULL)
350157184Sache		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
351157184Sache		  (UIDC *)malloc(sizeof(UIDC));
352157184Sache
353157184Sache	/*
354157184Sache	 * no match, look it up, if no match store it as an invalid entry,
355157184Sache	 * or store the matching uid
356157184Sache	 */
357157184Sache	if (ptr == NULL) {
358157184Sache		if ((pw = getpwnam(name)) == NULL)
359157184Sache			return(-1);
360157184Sache		*uid = pw->pw_uid;
361157184Sache		return(0);
362157184Sache	}
363157184Sache	(void)strncpy(ptr->name, name, UNMLEN - 1);
364157184Sache	ptr->name[UNMLEN-1] = '\0';
365157184Sache	if ((pw = getpwnam(name)) == NULL) {
366157184Sache		ptr->valid = INVALID;
367157184Sache		return(-1);
368157184Sache	}
369157184Sache	ptr->valid = VALID;
370157184Sache	*uid = ptr->uid = pw->pw_uid;
371157184Sache	return(0);
372157184Sache}
373157184Sache
374157184Sache/*
375157184Sache * gid_name()
376157184Sache *	caches the gid for a given group name. We use a simple hash table.
377119610Sache * Return
378119610Sache *	the gid (if any) for a group name, or a -1 if no match can be found
379119610Sache */
380119610Sache
381157184Sacheint
382157184Sachegid_name(char *name, gid_t *gid)
383157184Sache{
38421308Sache	struct group *gr;
38575406Sache	GIDC *ptr;
38675406Sache	int namelen;
387157184Sache
388157184Sache	/*
38921308Sache	 * return -1 for mangled names
390157184Sache	 */
391157184Sache	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
392157184Sache		return(-1);
393157184Sache	if ((grptb == NULL) && (grptb_start() < 0))
394157184Sache		return(-1);
395157184Sache
396157184Sache	/*
397157184Sache	 * look up in hash table, if found and valid return the uid,
398157184Sache	 * if found and invalid, return a -1
399157184Sache	 */
40021308Sache	ptr = grptb[st_hash(name, namelen, GID_SZ)];
401157184Sache	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
402157184Sache		if (ptr->valid == INVALID)
403157184Sache			return(-1);
404157184Sache		*gid = ptr->gid;
405157184Sache		return(0);
406157184Sache	}
407157184Sache
40821308Sache	if (!gropn) {
409157184Sache		setgroupent(1);
410119610Sache		++gropn;
411157184Sache	}
412157184Sache	if (ptr == NULL)
413157184Sache		ptr = grptb[st_hash(name, namelen, GID_SZ)] =
414157184Sache		  (GIDC *)malloc(sizeof(GIDC));
415157184Sache
416157184Sache	/*
417119610Sache	 * no match, look it up, if no match store it as an invalid entry,
418157184Sache	 * or store the matching gid
419157184Sache	 */
420157184Sache	if (ptr == NULL) {
421157184Sache		if ((gr = getgrnam(name)) == NULL)
422157184Sache			return(-1);
423157184Sache		*gid = gr->gr_gid;
424157184Sache		return(0);
425157184Sache	}
426157184Sache
42721308Sache	(void)strncpy(ptr->name, name, GNMLEN - 1);
428157184Sache	ptr->name[GNMLEN-1] = '\0';
429157184Sache	if ((gr = getgrnam(name)) == NULL) {
430157184Sache		ptr->valid = INVALID;
431157184Sache		return(-1);
432157184Sache	}
433157184Sache	ptr->valid = VALID;
434157184Sache	*gid = ptr->gid = gr->gr_gid;
435157184Sache	return(0);
43621308Sache}
437157184Sache