cache.c revision 76017
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1992 Keith Muller.
31556Srgrimes * Copyright (c) 1992, 1993
41556Srgrimes *	The Regents of the University of California.  All rights reserved.
51556Srgrimes *
61556Srgrimes * This code is derived from software contributed to Berkeley by
71556Srgrimes * Keith Muller of the University of California, San Diego.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 3. All advertising materials mentioning features or use of this software
181556Srgrimes *    must display the following acknowledgement:
191556Srgrimes *	This product includes software developed by the University of
201556Srgrimes *	California, Berkeley and its contributors.
211556Srgrimes * 4. Neither the name of the University nor the names of its contributors
221556Srgrimes *    may be used to endorse or promote products derived from this software
231556Srgrimes *    without specific prior written permission.
241556Srgrimes *
251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351556Srgrimes * SUCH DAMAGE.
361556Srgrimes */
371556Srgrimes
381556Srgrimes#ifndef lint
3936049Scharnier#if 0
4036049Scharnierstatic char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
4136049Scharnier#endif
4236049Scharnierstatic const char rcsid[] =
4350471Speter  "$FreeBSD: head/bin/pax/cache.c 76017 2001-04-26 08:37:00Z kris $";
441556Srgrimes#endif /* not lint */
451556Srgrimes
461556Srgrimes#include <sys/types.h>
471556Srgrimes#include <sys/stat.h>
481556Srgrimes#include <string.h>
491556Srgrimes#include <stdio.h>
501556Srgrimes#include <pwd.h>
511556Srgrimes#include <grp.h>
521556Srgrimes#include <unistd.h>
531556Srgrimes#include <stdlib.h>
541556Srgrimes#include "pax.h"
551556Srgrimes#include "cache.h"
561556Srgrimes#include "extern.h"
571556Srgrimes
581556Srgrimes/*
591556Srgrimes * routines that control user, group, uid and gid caches (for the archive
601556Srgrimes * member print routine).
611556Srgrimes * IMPORTANT:
621556Srgrimes * these routines cache BOTH hits and misses, a major performance improvement
631556Srgrimes */
641556Srgrimes
651556Srgrimesstatic	int pwopn = 0;		/* is password file open */
661556Srgrimesstatic	int gropn = 0;		/* is group file open */
671556Srgrimesstatic UIDC **uidtb = NULL;	/* uid to name cache */
681556Srgrimesstatic GIDC **gidtb = NULL;	/* gid to name cache */
691556Srgrimesstatic UIDC **usrtb = NULL;	/* user name to uid cache */
701556Srgrimesstatic GIDC **grptb = NULL;	/* group name to gid cache */
711556Srgrimes
721556Srgrimes/*
731556Srgrimes * uidtb_start
741556Srgrimes *	creates an an empty uidtb
751556Srgrimes * Return:
761556Srgrimes *	0 if ok, -1 otherwise
771556Srgrimes */
781556Srgrimes
7976017Skris#ifdef __STDC__
801556Srgrimesint
811556Srgrimesuidtb_start(void)
821556Srgrimes#else
831556Srgrimesint
841556Srgrimesuidtb_start()
851556Srgrimes#endif
861556Srgrimes{
871556Srgrimes	static int fail = 0;
881556Srgrimes
891556Srgrimes	if (uidtb != NULL)
901556Srgrimes		return(0);
911556Srgrimes	if (fail)
921556Srgrimes		return(-1);
931556Srgrimes	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
941556Srgrimes		++fail;
9576017Skris		paxwarn(1, "Unable to allocate memory for user id cache table");
961556Srgrimes		return(-1);
971556Srgrimes	}
981556Srgrimes	return(0);
991556Srgrimes}
1001556Srgrimes
1011556Srgrimes/*
1021556Srgrimes * gidtb_start
1031556Srgrimes *	creates an an empty gidtb
1041556Srgrimes * Return:
1051556Srgrimes *	0 if ok, -1 otherwise
1061556Srgrimes */
1071556Srgrimes
10876017Skris#ifdef __STDC__
1091556Srgrimesint
1101556Srgrimesgidtb_start(void)
1111556Srgrimes#else
1121556Srgrimesint
1131556Srgrimesgidtb_start()
1141556Srgrimes#endif
1151556Srgrimes{
1161556Srgrimes	static int fail = 0;
1171556Srgrimes
1181556Srgrimes	if (gidtb != NULL)
1191556Srgrimes		return(0);
1201556Srgrimes	if (fail)
1211556Srgrimes		return(-1);
1221556Srgrimes	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
1231556Srgrimes		++fail;
12476017Skris		paxwarn(1, "Unable to allocate memory for group id cache table");
1251556Srgrimes		return(-1);
1261556Srgrimes	}
1271556Srgrimes	return(0);
1281556Srgrimes}
1291556Srgrimes
1301556Srgrimes/*
1311556Srgrimes * usrtb_start
1321556Srgrimes *	creates an an empty usrtb
1331556Srgrimes * Return:
1341556Srgrimes *	0 if ok, -1 otherwise
1351556Srgrimes */
1361556Srgrimes
13776017Skris#ifdef __STDC__
1381556Srgrimesint
1391556Srgrimesusrtb_start(void)
1401556Srgrimes#else
1411556Srgrimesint
1421556Srgrimesusrtb_start()
1431556Srgrimes#endif
1441556Srgrimes{
1451556Srgrimes	static int fail = 0;
1461556Srgrimes
1471556Srgrimes	if (usrtb != NULL)
1481556Srgrimes		return(0);
1491556Srgrimes	if (fail)
1501556Srgrimes		return(-1);
1511556Srgrimes	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
1521556Srgrimes		++fail;
15376017Skris		paxwarn(1, "Unable to allocate memory for user name cache table");
1541556Srgrimes		return(-1);
1551556Srgrimes	}
1561556Srgrimes	return(0);
1571556Srgrimes}
1581556Srgrimes
1591556Srgrimes/*
1601556Srgrimes * grptb_start
1611556Srgrimes *	creates an an empty grptb
1621556Srgrimes * Return:
1631556Srgrimes *	0 if ok, -1 otherwise
1641556Srgrimes */
1651556Srgrimes
16676017Skris#ifdef __STDC__
1671556Srgrimesint
1681556Srgrimesgrptb_start(void)
1691556Srgrimes#else
1701556Srgrimesint
1711556Srgrimesgrptb_start()
1721556Srgrimes#endif
1731556Srgrimes{
1741556Srgrimes	static int fail = 0;
1751556Srgrimes
1761556Srgrimes	if (grptb != NULL)
1771556Srgrimes		return(0);
1781556Srgrimes	if (fail)
1791556Srgrimes		return(-1);
1801556Srgrimes	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
1811556Srgrimes		++fail;
18276017Skris		paxwarn(1,"Unable to allocate memory for group name cache table");
1831556Srgrimes		return(-1);
1841556Srgrimes	}
1851556Srgrimes	return(0);
1861556Srgrimes}
1871556Srgrimes
1881556Srgrimes/*
1891556Srgrimes * name_uid()
1901556Srgrimes *	caches the name (if any) for the uid. If frc set, we always return the
1911556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
1921556Srgrimes * Return
1931556Srgrimes *	Pointer to stored name (or a empty string)
1941556Srgrimes */
1951556Srgrimes
19676017Skris#ifdef __STDC__
1971556Srgrimeschar *
1981556Srgrimesname_uid(uid_t uid, int frc)
1991556Srgrimes#else
2001556Srgrimeschar *
2011556Srgrimesname_uid(uid, frc)
2021556Srgrimes	uid_t uid;
2031556Srgrimes	int frc;
2041556Srgrimes#endif
2051556Srgrimes{
2061556Srgrimes	register struct passwd *pw;
2071556Srgrimes	register UIDC *ptr;
2081556Srgrimes
2091556Srgrimes	if ((uidtb == NULL) && (uidtb_start() < 0))
2101556Srgrimes		return("");
2111556Srgrimes
2121556Srgrimes	/*
2131556Srgrimes	 * see if we have this uid cached
2141556Srgrimes	 */
2151556Srgrimes	ptr = uidtb[uid % UID_SZ];
2161556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
2171556Srgrimes		/*
2181556Srgrimes		 * have an entry for this uid
2191556Srgrimes		 */
2201556Srgrimes		if (frc || (ptr->valid == VALID))
2211556Srgrimes			return(ptr->name);
2221556Srgrimes		return("");
2231556Srgrimes	}
2241556Srgrimes
2251556Srgrimes	/*
2261556Srgrimes	 * No entry for this uid, we will add it
2271556Srgrimes	 */
2281556Srgrimes	if (!pwopn) {
2291556Srgrimes		setpassent(1);
2301556Srgrimes		++pwopn;
2311556Srgrimes	}
2321556Srgrimes	if (ptr == NULL)
2331556Srgrimes		ptr = (UIDC *)malloc(sizeof(UIDC));
2341556Srgrimes
2351556Srgrimes	if ((pw = getpwuid(uid)) == NULL) {
2361556Srgrimes		/*
2371556Srgrimes		 * no match for this uid in the local password file
23846684Skris		 * a string that is the uid in numeric format
2391556Srgrimes		 */
2401556Srgrimes		if (ptr == NULL)
2411556Srgrimes			return("");
2421556Srgrimes		ptr->uid = uid;
2431556Srgrimes		ptr->valid = INVALID;
2441556Srgrimes#		ifdef NET2_STAT
24576017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
2461556Srgrimes#		else
24776017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
24876017Skris			       (unsigned long)uid);
2491556Srgrimes#		endif
2501556Srgrimes		if (frc == 0)
2511556Srgrimes			return("");
2521556Srgrimes	} else {
2531556Srgrimes		/*
2541556Srgrimes		 * there is an entry for this uid in the password file
2551556Srgrimes		 */
2561556Srgrimes		if (ptr == NULL)
2571556Srgrimes			return(pw->pw_name);
2581556Srgrimes		ptr->uid = uid;
25926363Scharnier		(void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
2601556Srgrimes		ptr->name[UNMLEN-1] = '\0';
2611556Srgrimes		ptr->valid = VALID;
2621556Srgrimes	}
2631556Srgrimes	return(ptr->name);
2641556Srgrimes}
2651556Srgrimes
2661556Srgrimes/*
2671556Srgrimes * name_gid()
2681556Srgrimes *	caches the name (if any) for the gid. If frc set, we always return the
2691556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
2701556Srgrimes * Return
2711556Srgrimes *	Pointer to stored name (or a empty string)
2721556Srgrimes */
2731556Srgrimes
27476017Skris#ifdef __STDC__
2751556Srgrimeschar *
2761556Srgrimesname_gid(gid_t gid, int frc)
2771556Srgrimes#else
2781556Srgrimeschar *
2791556Srgrimesname_gid(gid, frc)
2801556Srgrimes	gid_t gid;
2811556Srgrimes	int frc;
2821556Srgrimes#endif
2831556Srgrimes{
2841556Srgrimes	register struct group *gr;
2851556Srgrimes	register GIDC *ptr;
2861556Srgrimes
2871556Srgrimes	if ((gidtb == NULL) && (gidtb_start() < 0))
2881556Srgrimes		return("");
2891556Srgrimes
2901556Srgrimes	/*
2911556Srgrimes	 * see if we have this gid cached
2921556Srgrimes	 */
2931556Srgrimes	ptr = gidtb[gid % GID_SZ];
2941556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
2951556Srgrimes		/*
2961556Srgrimes		 * have an entry for this gid
2971556Srgrimes		 */
2981556Srgrimes		if (frc || (ptr->valid == VALID))
2991556Srgrimes			return(ptr->name);
3001556Srgrimes		return("");
3011556Srgrimes	}
3021556Srgrimes
3031556Srgrimes	/*
3041556Srgrimes	 * No entry for this gid, we will add it
3051556Srgrimes	 */
3061556Srgrimes	if (!gropn) {
3071556Srgrimes		setgroupent(1);
3081556Srgrimes		++gropn;
3091556Srgrimes	}
3101556Srgrimes	if (ptr == NULL)
3111556Srgrimes		ptr = (GIDC *)malloc(sizeof(GIDC));
3121556Srgrimes
3131556Srgrimes	if ((gr = getgrgid(gid)) == NULL) {
3141556Srgrimes		/*
3151556Srgrimes		 * no match for this gid in the local group file, put in
31646684Skris		 * a string that is the gid in numeric format
3171556Srgrimes		 */
3181556Srgrimes		if (ptr == NULL)
3191556Srgrimes			return("");
3201556Srgrimes		ptr->gid = gid;
3211556Srgrimes		ptr->valid = INVALID;
3221556Srgrimes#		ifdef NET2_STAT
32376017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
3241556Srgrimes#		else
32576017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
32676017Skris			       (unsigned long)gid);
3271556Srgrimes#		endif
3281556Srgrimes		if (frc == 0)
3291556Srgrimes			return("");
3301556Srgrimes	} else {
3311556Srgrimes		/*
3321556Srgrimes		 * there is an entry for this group in the group file
3331556Srgrimes		 */
3341556Srgrimes		if (ptr == NULL)
3351556Srgrimes			return(gr->gr_name);
3361556Srgrimes		ptr->gid = gid;
33726363Scharnier		(void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
3381556Srgrimes		ptr->name[GNMLEN-1] = '\0';
3391556Srgrimes		ptr->valid = VALID;
3401556Srgrimes	}
3411556Srgrimes	return(ptr->name);
3421556Srgrimes}
3431556Srgrimes
3441556Srgrimes/*
3451556Srgrimes * uid_name()
3461556Srgrimes *	caches the uid for a given user name. We use a simple hash table.
3471556Srgrimes * Return
3481556Srgrimes *	the uid (if any) for a user name, or a -1 if no match can be found
3491556Srgrimes */
3501556Srgrimes
35176017Skris#ifdef __STDC__
3521556Srgrimesint
3531556Srgrimesuid_name(char *name, uid_t *uid)
3541556Srgrimes#else
3551556Srgrimesint
3561556Srgrimesuid_name(name, uid)
3571556Srgrimes	char *name;
3581556Srgrimes	uid_t *uid;
3591556Srgrimes#endif
3601556Srgrimes{
3611556Srgrimes	register struct passwd *pw;
3621556Srgrimes	register UIDC *ptr;
3631556Srgrimes	register int namelen;
3641556Srgrimes
3651556Srgrimes	/*
3661556Srgrimes	 * return -1 for mangled names
3671556Srgrimes	 */
3681556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3691556Srgrimes		return(-1);
3701556Srgrimes	if ((usrtb == NULL) && (usrtb_start() < 0))
3711556Srgrimes		return(-1);
3721556Srgrimes
3731556Srgrimes	/*
3741556Srgrimes	 * look up in hash table, if found and valid return the uid,
3751556Srgrimes	 * if found and invalid, return a -1
3761556Srgrimes	 */
3771556Srgrimes	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
3781556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3791556Srgrimes		if (ptr->valid == INVALID)
3801556Srgrimes			return(-1);
3811556Srgrimes		*uid = ptr->uid;
3821556Srgrimes		return(0);
3831556Srgrimes	}
3841556Srgrimes
3851556Srgrimes	if (!pwopn) {
3861556Srgrimes		setpassent(1);
3871556Srgrimes		++pwopn;
3881556Srgrimes	}
3891556Srgrimes
3901556Srgrimes	if (ptr == NULL)
3911556Srgrimes		ptr = (UIDC *)malloc(sizeof(UIDC));
3921556Srgrimes
3931556Srgrimes	/*
3941556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
3951556Srgrimes	 * or store the matching uid
3961556Srgrimes	 */
3971556Srgrimes	if (ptr == NULL) {
3981556Srgrimes		if ((pw = getpwnam(name)) == NULL)
3991556Srgrimes			return(-1);
4001556Srgrimes		*uid = pw->pw_uid;
4011556Srgrimes		return(0);
4021556Srgrimes	}
40326363Scharnier	(void)strncpy(ptr->name, name, UNMLEN - 1);
4041556Srgrimes	ptr->name[UNMLEN-1] = '\0';
4051556Srgrimes	if ((pw = getpwnam(name)) == NULL) {
4061556Srgrimes		ptr->valid = INVALID;
4071556Srgrimes		return(-1);
4081556Srgrimes	}
4091556Srgrimes	ptr->valid = VALID;
4101556Srgrimes	*uid = ptr->uid = pw->pw_uid;
4111556Srgrimes	return(0);
4121556Srgrimes}
4131556Srgrimes
4141556Srgrimes/*
4151556Srgrimes * gid_name()
4161556Srgrimes *	caches the gid for a given group name. We use a simple hash table.
4171556Srgrimes * Return
4181556Srgrimes *	the gid (if any) for a group name, or a -1 if no match can be found
4191556Srgrimes */
4201556Srgrimes
42176017Skris#ifdef __STDC__
4221556Srgrimesint
4231556Srgrimesgid_name(char *name, gid_t *gid)
4241556Srgrimes#else
4251556Srgrimesint
4261556Srgrimesgid_name(name, gid)
4271556Srgrimes	char *name;
4281556Srgrimes	gid_t *gid;
4291556Srgrimes#endif
4301556Srgrimes{
4311556Srgrimes	register struct group *gr;
4321556Srgrimes	register GIDC *ptr;
4331556Srgrimes	register int namelen;
4341556Srgrimes
4351556Srgrimes	/*
4361556Srgrimes	 * return -1 for mangled names
4371556Srgrimes	 */
4381556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
4391556Srgrimes		return(-1);
4401556Srgrimes	if ((grptb == NULL) && (grptb_start() < 0))
4411556Srgrimes		return(-1);
4421556Srgrimes
4431556Srgrimes	/*
4441556Srgrimes	 * look up in hash table, if found and valid return the uid,
4451556Srgrimes	 * if found and invalid, return a -1
4461556Srgrimes	 */
4471556Srgrimes	ptr = grptb[st_hash(name, namelen, GID_SZ)];
4481556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
4491556Srgrimes		if (ptr->valid == INVALID)
4501556Srgrimes			return(-1);
4511556Srgrimes		*gid = ptr->gid;
4521556Srgrimes		return(0);
4531556Srgrimes	}
4541556Srgrimes
4551556Srgrimes	if (!gropn) {
4561556Srgrimes		setgroupent(1);
4571556Srgrimes		++gropn;
4581556Srgrimes	}
4591556Srgrimes	if (ptr == NULL)
4601556Srgrimes		ptr = (GIDC *)malloc(sizeof(GIDC));
4611556Srgrimes
4621556Srgrimes	/*
4631556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
4641556Srgrimes	 * or store the matching gid
4651556Srgrimes	 */
4661556Srgrimes	if (ptr == NULL) {
4671556Srgrimes		if ((gr = getgrnam(name)) == NULL)
4681556Srgrimes			return(-1);
4691556Srgrimes		*gid = gr->gr_gid;
4701556Srgrimes		return(0);
4711556Srgrimes	}
4721556Srgrimes
47326363Scharnier	(void)strncpy(ptr->name, name, GNMLEN - 1);
4741556Srgrimes	ptr->name[GNMLEN-1] = '\0';
4751556Srgrimes	if ((gr = getgrnam(name)) == NULL) {
4761556Srgrimes		ptr->valid = INVALID;
4771556Srgrimes		return(-1);
4781556Srgrimes	}
4791556Srgrimes	ptr->valid = VALID;
4801556Srgrimes	*gid = ptr->gid = gr->gr_gid;
4811556Srgrimes	return(0);
4821556Srgrimes}
483