cache.c revision 90113
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 90113 2002-02-02 07:07:59Z imp $";
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
791556Srgrimesint
801556Srgrimesuidtb_start(void)
811556Srgrimes{
821556Srgrimes	static int fail = 0;
831556Srgrimes
841556Srgrimes	if (uidtb != NULL)
851556Srgrimes		return(0);
861556Srgrimes	if (fail)
871556Srgrimes		return(-1);
881556Srgrimes	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
891556Srgrimes		++fail;
9076017Skris		paxwarn(1, "Unable to allocate memory for user id cache table");
911556Srgrimes		return(-1);
921556Srgrimes	}
931556Srgrimes	return(0);
941556Srgrimes}
951556Srgrimes
961556Srgrimes/*
971556Srgrimes * gidtb_start
981556Srgrimes *	creates an an empty gidtb
991556Srgrimes * Return:
1001556Srgrimes *	0 if ok, -1 otherwise
1011556Srgrimes */
1021556Srgrimes
1031556Srgrimesint
1041556Srgrimesgidtb_start(void)
1051556Srgrimes{
1061556Srgrimes	static int fail = 0;
1071556Srgrimes
1081556Srgrimes	if (gidtb != NULL)
1091556Srgrimes		return(0);
1101556Srgrimes	if (fail)
1111556Srgrimes		return(-1);
1121556Srgrimes	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
1131556Srgrimes		++fail;
11476017Skris		paxwarn(1, "Unable to allocate memory for group id cache table");
1151556Srgrimes		return(-1);
1161556Srgrimes	}
1171556Srgrimes	return(0);
1181556Srgrimes}
1191556Srgrimes
1201556Srgrimes/*
1211556Srgrimes * usrtb_start
1221556Srgrimes *	creates an an empty usrtb
1231556Srgrimes * Return:
1241556Srgrimes *	0 if ok, -1 otherwise
1251556Srgrimes */
1261556Srgrimes
1271556Srgrimesint
1281556Srgrimesusrtb_start(void)
1291556Srgrimes{
1301556Srgrimes	static int fail = 0;
1311556Srgrimes
1321556Srgrimes	if (usrtb != NULL)
1331556Srgrimes		return(0);
1341556Srgrimes	if (fail)
1351556Srgrimes		return(-1);
1361556Srgrimes	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
1371556Srgrimes		++fail;
13876017Skris		paxwarn(1, "Unable to allocate memory for user name cache table");
1391556Srgrimes		return(-1);
1401556Srgrimes	}
1411556Srgrimes	return(0);
1421556Srgrimes}
1431556Srgrimes
1441556Srgrimes/*
1451556Srgrimes * grptb_start
1461556Srgrimes *	creates an an empty grptb
1471556Srgrimes * Return:
1481556Srgrimes *	0 if ok, -1 otherwise
1491556Srgrimes */
1501556Srgrimes
1511556Srgrimesint
1521556Srgrimesgrptb_start(void)
1531556Srgrimes{
1541556Srgrimes	static int fail = 0;
1551556Srgrimes
1561556Srgrimes	if (grptb != NULL)
1571556Srgrimes		return(0);
1581556Srgrimes	if (fail)
1591556Srgrimes		return(-1);
1601556Srgrimes	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
1611556Srgrimes		++fail;
16276017Skris		paxwarn(1,"Unable to allocate memory for group name cache table");
1631556Srgrimes		return(-1);
1641556Srgrimes	}
1651556Srgrimes	return(0);
1661556Srgrimes}
1671556Srgrimes
1681556Srgrimes/*
1691556Srgrimes * name_uid()
1701556Srgrimes *	caches the name (if any) for the uid. If frc set, we always return the
1711556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
1721556Srgrimes * Return
1731556Srgrimes *	Pointer to stored name (or a empty string)
1741556Srgrimes */
1751556Srgrimes
1761556Srgrimeschar *
1771556Srgrimesname_uid(uid_t uid, int frc)
1781556Srgrimes{
17990113Simp	struct passwd *pw;
18090113Simp	UIDC *ptr;
1811556Srgrimes
1821556Srgrimes	if ((uidtb == NULL) && (uidtb_start() < 0))
1831556Srgrimes		return("");
1841556Srgrimes
1851556Srgrimes	/*
1861556Srgrimes	 * see if we have this uid cached
1871556Srgrimes	 */
1881556Srgrimes	ptr = uidtb[uid % UID_SZ];
1891556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
1901556Srgrimes		/*
1911556Srgrimes		 * have an entry for this uid
1921556Srgrimes		 */
1931556Srgrimes		if (frc || (ptr->valid == VALID))
1941556Srgrimes			return(ptr->name);
1951556Srgrimes		return("");
1961556Srgrimes	}
1971556Srgrimes
1981556Srgrimes	/*
1991556Srgrimes	 * No entry for this uid, we will add it
2001556Srgrimes	 */
2011556Srgrimes	if (!pwopn) {
2021556Srgrimes		setpassent(1);
2031556Srgrimes		++pwopn;
2041556Srgrimes	}
2051556Srgrimes	if (ptr == NULL)
2061556Srgrimes		ptr = (UIDC *)malloc(sizeof(UIDC));
2071556Srgrimes
2081556Srgrimes	if ((pw = getpwuid(uid)) == NULL) {
2091556Srgrimes		/*
2101556Srgrimes		 * no match for this uid in the local password file
21146684Skris		 * a string that is the uid in numeric format
2121556Srgrimes		 */
2131556Srgrimes		if (ptr == NULL)
2141556Srgrimes			return("");
2151556Srgrimes		ptr->uid = uid;
2161556Srgrimes		ptr->valid = INVALID;
2171556Srgrimes#		ifdef NET2_STAT
21876017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
2191556Srgrimes#		else
22076017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
22176017Skris			       (unsigned long)uid);
2221556Srgrimes#		endif
2231556Srgrimes		if (frc == 0)
2241556Srgrimes			return("");
2251556Srgrimes	} else {
2261556Srgrimes		/*
2271556Srgrimes		 * there is an entry for this uid in the password file
2281556Srgrimes		 */
2291556Srgrimes		if (ptr == NULL)
2301556Srgrimes			return(pw->pw_name);
2311556Srgrimes		ptr->uid = uid;
23226363Scharnier		(void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
2331556Srgrimes		ptr->name[UNMLEN-1] = '\0';
2341556Srgrimes		ptr->valid = VALID;
2351556Srgrimes	}
2361556Srgrimes	return(ptr->name);
2371556Srgrimes}
2381556Srgrimes
2391556Srgrimes/*
2401556Srgrimes * name_gid()
2411556Srgrimes *	caches the name (if any) for the gid. If frc set, we always return the
2421556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
2431556Srgrimes * Return
2441556Srgrimes *	Pointer to stored name (or a empty string)
2451556Srgrimes */
2461556Srgrimes
2471556Srgrimeschar *
2481556Srgrimesname_gid(gid_t gid, int frc)
2491556Srgrimes{
25090113Simp	struct group *gr;
25190113Simp	GIDC *ptr;
2521556Srgrimes
2531556Srgrimes	if ((gidtb == NULL) && (gidtb_start() < 0))
2541556Srgrimes		return("");
2551556Srgrimes
2561556Srgrimes	/*
2571556Srgrimes	 * see if we have this gid cached
2581556Srgrimes	 */
2591556Srgrimes	ptr = gidtb[gid % GID_SZ];
2601556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
2611556Srgrimes		/*
2621556Srgrimes		 * have an entry for this gid
2631556Srgrimes		 */
2641556Srgrimes		if (frc || (ptr->valid == VALID))
2651556Srgrimes			return(ptr->name);
2661556Srgrimes		return("");
2671556Srgrimes	}
2681556Srgrimes
2691556Srgrimes	/*
2701556Srgrimes	 * No entry for this gid, we will add it
2711556Srgrimes	 */
2721556Srgrimes	if (!gropn) {
2731556Srgrimes		setgroupent(1);
2741556Srgrimes		++gropn;
2751556Srgrimes	}
2761556Srgrimes	if (ptr == NULL)
2771556Srgrimes		ptr = (GIDC *)malloc(sizeof(GIDC));
2781556Srgrimes
2791556Srgrimes	if ((gr = getgrgid(gid)) == NULL) {
2801556Srgrimes		/*
2811556Srgrimes		 * no match for this gid in the local group file, put in
28246684Skris		 * a string that is the gid in numeric format
2831556Srgrimes		 */
2841556Srgrimes		if (ptr == NULL)
2851556Srgrimes			return("");
2861556Srgrimes		ptr->gid = gid;
2871556Srgrimes		ptr->valid = INVALID;
2881556Srgrimes#		ifdef NET2_STAT
28976017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
2901556Srgrimes#		else
29176017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
29276017Skris			       (unsigned long)gid);
2931556Srgrimes#		endif
2941556Srgrimes		if (frc == 0)
2951556Srgrimes			return("");
2961556Srgrimes	} else {
2971556Srgrimes		/*
2981556Srgrimes		 * there is an entry for this group in the group file
2991556Srgrimes		 */
3001556Srgrimes		if (ptr == NULL)
3011556Srgrimes			return(gr->gr_name);
3021556Srgrimes		ptr->gid = gid;
30326363Scharnier		(void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
3041556Srgrimes		ptr->name[GNMLEN-1] = '\0';
3051556Srgrimes		ptr->valid = VALID;
3061556Srgrimes	}
3071556Srgrimes	return(ptr->name);
3081556Srgrimes}
3091556Srgrimes
3101556Srgrimes/*
3111556Srgrimes * uid_name()
3121556Srgrimes *	caches the uid for a given user name. We use a simple hash table.
3131556Srgrimes * Return
3141556Srgrimes *	the uid (if any) for a user name, or a -1 if no match can be found
3151556Srgrimes */
3161556Srgrimes
3171556Srgrimesint
3181556Srgrimesuid_name(char *name, uid_t *uid)
3191556Srgrimes{
32090113Simp	struct passwd *pw;
32190113Simp	UIDC *ptr;
32290113Simp	int namelen;
3231556Srgrimes
3241556Srgrimes	/*
3251556Srgrimes	 * return -1 for mangled names
3261556Srgrimes	 */
3271556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3281556Srgrimes		return(-1);
3291556Srgrimes	if ((usrtb == NULL) && (usrtb_start() < 0))
3301556Srgrimes		return(-1);
3311556Srgrimes
3321556Srgrimes	/*
3331556Srgrimes	 * look up in hash table, if found and valid return the uid,
3341556Srgrimes	 * if found and invalid, return a -1
3351556Srgrimes	 */
3361556Srgrimes	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
3371556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3381556Srgrimes		if (ptr->valid == INVALID)
3391556Srgrimes			return(-1);
3401556Srgrimes		*uid = ptr->uid;
3411556Srgrimes		return(0);
3421556Srgrimes	}
3431556Srgrimes
3441556Srgrimes	if (!pwopn) {
3451556Srgrimes		setpassent(1);
3461556Srgrimes		++pwopn;
3471556Srgrimes	}
3481556Srgrimes
3491556Srgrimes	if (ptr == NULL)
35076351Skris		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
35176351Skris		  (UIDC *)malloc(sizeof(UIDC));
3521556Srgrimes
3531556Srgrimes	/*
3541556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
3551556Srgrimes	 * or store the matching uid
3561556Srgrimes	 */
3571556Srgrimes	if (ptr == NULL) {
3581556Srgrimes		if ((pw = getpwnam(name)) == NULL)
3591556Srgrimes			return(-1);
3601556Srgrimes		*uid = pw->pw_uid;
3611556Srgrimes		return(0);
3621556Srgrimes	}
36326363Scharnier	(void)strncpy(ptr->name, name, UNMLEN - 1);
3641556Srgrimes	ptr->name[UNMLEN-1] = '\0';
3651556Srgrimes	if ((pw = getpwnam(name)) == NULL) {
3661556Srgrimes		ptr->valid = INVALID;
3671556Srgrimes		return(-1);
3681556Srgrimes	}
3691556Srgrimes	ptr->valid = VALID;
3701556Srgrimes	*uid = ptr->uid = pw->pw_uid;
3711556Srgrimes	return(0);
3721556Srgrimes}
3731556Srgrimes
3741556Srgrimes/*
3751556Srgrimes * gid_name()
3761556Srgrimes *	caches the gid for a given group name. We use a simple hash table.
3771556Srgrimes * Return
3781556Srgrimes *	the gid (if any) for a group name, or a -1 if no match can be found
3791556Srgrimes */
3801556Srgrimes
3811556Srgrimesint
3821556Srgrimesgid_name(char *name, gid_t *gid)
3831556Srgrimes{
38490113Simp	struct group *gr;
38590113Simp	GIDC *ptr;
38690113Simp	int namelen;
3871556Srgrimes
3881556Srgrimes	/*
3891556Srgrimes	 * return -1 for mangled names
3901556Srgrimes	 */
3911556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3921556Srgrimes		return(-1);
3931556Srgrimes	if ((grptb == NULL) && (grptb_start() < 0))
3941556Srgrimes		return(-1);
3951556Srgrimes
3961556Srgrimes	/*
3971556Srgrimes	 * look up in hash table, if found and valid return the uid,
3981556Srgrimes	 * if found and invalid, return a -1
3991556Srgrimes	 */
4001556Srgrimes	ptr = grptb[st_hash(name, namelen, GID_SZ)];
4011556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
4021556Srgrimes		if (ptr->valid == INVALID)
4031556Srgrimes			return(-1);
4041556Srgrimes		*gid = ptr->gid;
4051556Srgrimes		return(0);
4061556Srgrimes	}
4071556Srgrimes
4081556Srgrimes	if (!gropn) {
4091556Srgrimes		setgroupent(1);
4101556Srgrimes		++gropn;
4111556Srgrimes	}
4121556Srgrimes	if (ptr == NULL)
41376351Skris		ptr = grptb[st_hash(name, namelen, GID_SZ)] =
41476351Skris		  (GIDC *)malloc(sizeof(GIDC));
4151556Srgrimes
4161556Srgrimes	/*
4171556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
4181556Srgrimes	 * or store the matching gid
4191556Srgrimes	 */
4201556Srgrimes	if (ptr == NULL) {
4211556Srgrimes		if ((gr = getgrnam(name)) == NULL)
4221556Srgrimes			return(-1);
4231556Srgrimes		*gid = gr->gr_gid;
4241556Srgrimes		return(0);
4251556Srgrimes	}
4261556Srgrimes
42726363Scharnier	(void)strncpy(ptr->name, name, GNMLEN - 1);
4281556Srgrimes	ptr->name[GNMLEN-1] = '\0';
4291556Srgrimes	if ((gr = getgrnam(name)) == NULL) {
4301556Srgrimes		ptr->valid = INVALID;
4311556Srgrimes		return(-1);
4321556Srgrimes	}
4331556Srgrimes	ptr->valid = VALID;
4341556Srgrimes	*gid = ptr->gid = gr->gr_gid;
4351556Srgrimes	return(0);
4361556Srgrimes}
437