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 * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3536049Scharnier#if 0
3636049Scharnierstatic char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
3736049Scharnier#endif
381556Srgrimes#endif /* not lint */
3999110Sobrien#include <sys/cdefs.h>
4099110Sobrien__FBSDID("$FreeBSD$");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes#include <sys/stat.h>
441556Srgrimes#include <string.h>
451556Srgrimes#include <stdio.h>
461556Srgrimes#include <pwd.h>
471556Srgrimes#include <grp.h>
481556Srgrimes#include <stdlib.h>
491556Srgrimes#include "pax.h"
501556Srgrimes#include "cache.h"
511556Srgrimes#include "extern.h"
521556Srgrimes
531556Srgrimes/*
541556Srgrimes * routines that control user, group, uid and gid caches (for the archive
551556Srgrimes * member print routine).
561556Srgrimes * IMPORTANT:
571556Srgrimes * these routines cache BOTH hits and misses, a major performance improvement
581556Srgrimes */
591556Srgrimes
601556Srgrimesstatic	int pwopn = 0;		/* is password file open */
611556Srgrimesstatic	int gropn = 0;		/* is group file open */
621556Srgrimesstatic UIDC **uidtb = NULL;	/* uid to name cache */
631556Srgrimesstatic GIDC **gidtb = NULL;	/* gid to name cache */
641556Srgrimesstatic UIDC **usrtb = NULL;	/* user name to uid cache */
651556Srgrimesstatic GIDC **grptb = NULL;	/* group name to gid cache */
661556Srgrimes
671556Srgrimes/*
681556Srgrimes * uidtb_start
691556Srgrimes *	creates an an empty uidtb
701556Srgrimes * Return:
711556Srgrimes *	0 if ok, -1 otherwise
721556Srgrimes */
731556Srgrimes
741556Srgrimesint
751556Srgrimesuidtb_start(void)
761556Srgrimes{
771556Srgrimes	static int fail = 0;
781556Srgrimes
791556Srgrimes	if (uidtb != NULL)
801556Srgrimes		return(0);
811556Srgrimes	if (fail)
821556Srgrimes		return(-1);
831556Srgrimes	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
841556Srgrimes		++fail;
8576017Skris		paxwarn(1, "Unable to allocate memory for user id cache table");
861556Srgrimes		return(-1);
871556Srgrimes	}
881556Srgrimes	return(0);
891556Srgrimes}
901556Srgrimes
911556Srgrimes/*
921556Srgrimes * gidtb_start
931556Srgrimes *	creates an an empty gidtb
941556Srgrimes * Return:
951556Srgrimes *	0 if ok, -1 otherwise
961556Srgrimes */
971556Srgrimes
981556Srgrimesint
991556Srgrimesgidtb_start(void)
1001556Srgrimes{
1011556Srgrimes	static int fail = 0;
1021556Srgrimes
1031556Srgrimes	if (gidtb != NULL)
1041556Srgrimes		return(0);
1051556Srgrimes	if (fail)
1061556Srgrimes		return(-1);
1071556Srgrimes	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
1081556Srgrimes		++fail;
10976017Skris		paxwarn(1, "Unable to allocate memory for group id cache table");
1101556Srgrimes		return(-1);
1111556Srgrimes	}
1121556Srgrimes	return(0);
1131556Srgrimes}
1141556Srgrimes
1151556Srgrimes/*
1161556Srgrimes * usrtb_start
1171556Srgrimes *	creates an an empty usrtb
1181556Srgrimes * Return:
1191556Srgrimes *	0 if ok, -1 otherwise
1201556Srgrimes */
1211556Srgrimes
1221556Srgrimesint
1231556Srgrimesusrtb_start(void)
1241556Srgrimes{
1251556Srgrimes	static int fail = 0;
1261556Srgrimes
1271556Srgrimes	if (usrtb != NULL)
1281556Srgrimes		return(0);
1291556Srgrimes	if (fail)
1301556Srgrimes		return(-1);
1311556Srgrimes	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
1321556Srgrimes		++fail;
13376017Skris		paxwarn(1, "Unable to allocate memory for user name cache table");
1341556Srgrimes		return(-1);
1351556Srgrimes	}
1361556Srgrimes	return(0);
1371556Srgrimes}
1381556Srgrimes
1391556Srgrimes/*
1401556Srgrimes * grptb_start
1411556Srgrimes *	creates an an empty grptb
1421556Srgrimes * Return:
1431556Srgrimes *	0 if ok, -1 otherwise
1441556Srgrimes */
1451556Srgrimes
1461556Srgrimesint
1471556Srgrimesgrptb_start(void)
1481556Srgrimes{
1491556Srgrimes	static int fail = 0;
1501556Srgrimes
1511556Srgrimes	if (grptb != NULL)
1521556Srgrimes		return(0);
1531556Srgrimes	if (fail)
1541556Srgrimes		return(-1);
1551556Srgrimes	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
1561556Srgrimes		++fail;
15776017Skris		paxwarn(1,"Unable to allocate memory for group name cache table");
1581556Srgrimes		return(-1);
1591556Srgrimes	}
1601556Srgrimes	return(0);
1611556Srgrimes}
1621556Srgrimes
1631556Srgrimes/*
1641556Srgrimes * name_uid()
1651556Srgrimes *	caches the name (if any) for the uid. If frc set, we always return the
1661556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
1671556Srgrimes * Return
168108533Sschweikh *	Pointer to stored name (or an empty string).
1691556Srgrimes */
1701556Srgrimes
171114583Smarkmconst char *
1721556Srgrimesname_uid(uid_t uid, int frc)
1731556Srgrimes{
17490113Simp	struct passwd *pw;
17590113Simp	UIDC *ptr;
1761556Srgrimes
1771556Srgrimes	if ((uidtb == NULL) && (uidtb_start() < 0))
1781556Srgrimes		return("");
1791556Srgrimes
1801556Srgrimes	/*
1811556Srgrimes	 * see if we have this uid cached
1821556Srgrimes	 */
1831556Srgrimes	ptr = uidtb[uid % UID_SZ];
1841556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
1851556Srgrimes		/*
1861556Srgrimes		 * have an entry for this uid
1871556Srgrimes		 */
1881556Srgrimes		if (frc || (ptr->valid == VALID))
1891556Srgrimes			return(ptr->name);
1901556Srgrimes		return("");
1911556Srgrimes	}
1921556Srgrimes
1931556Srgrimes	/*
1941556Srgrimes	 * No entry for this uid, we will add it
1951556Srgrimes	 */
1961556Srgrimes	if (!pwopn) {
1971556Srgrimes		setpassent(1);
1981556Srgrimes		++pwopn;
1991556Srgrimes	}
2001556Srgrimes	if (ptr == NULL)
201127055Scperciva		ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC));
2021556Srgrimes
2031556Srgrimes	if ((pw = getpwuid(uid)) == NULL) {
2041556Srgrimes		/*
2051556Srgrimes		 * no match for this uid in the local password file
20646684Skris		 * a string that is the uid in numeric format
2071556Srgrimes		 */
2081556Srgrimes		if (ptr == NULL)
2091556Srgrimes			return("");
2101556Srgrimes		ptr->uid = uid;
2111556Srgrimes		ptr->valid = INVALID;
2121556Srgrimes#		ifdef NET2_STAT
21376017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
2141556Srgrimes#		else
21576017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
21676017Skris			       (unsigned long)uid);
2171556Srgrimes#		endif
2181556Srgrimes		if (frc == 0)
2191556Srgrimes			return("");
2201556Srgrimes	} else {
2211556Srgrimes		/*
2221556Srgrimes		 * there is an entry for this uid in the password file
2231556Srgrimes		 */
2241556Srgrimes		if (ptr == NULL)
2251556Srgrimes			return(pw->pw_name);
2261556Srgrimes		ptr->uid = uid;
22726363Scharnier		(void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
2281556Srgrimes		ptr->name[UNMLEN-1] = '\0';
2291556Srgrimes		ptr->valid = VALID;
2301556Srgrimes	}
2311556Srgrimes	return(ptr->name);
2321556Srgrimes}
2331556Srgrimes
2341556Srgrimes/*
2351556Srgrimes * name_gid()
2361556Srgrimes *	caches the name (if any) for the gid. If frc set, we always return the
2371556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
2381556Srgrimes * Return
239108533Sschweikh *	Pointer to stored name (or an empty string).
2401556Srgrimes */
2411556Srgrimes
242114583Smarkmconst char *
2431556Srgrimesname_gid(gid_t gid, int frc)
2441556Srgrimes{
24590113Simp	struct group *gr;
24690113Simp	GIDC *ptr;
2471556Srgrimes
2481556Srgrimes	if ((gidtb == NULL) && (gidtb_start() < 0))
2491556Srgrimes		return("");
2501556Srgrimes
2511556Srgrimes	/*
2521556Srgrimes	 * see if we have this gid cached
2531556Srgrimes	 */
2541556Srgrimes	ptr = gidtb[gid % GID_SZ];
2551556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
2561556Srgrimes		/*
2571556Srgrimes		 * have an entry for this gid
2581556Srgrimes		 */
2591556Srgrimes		if (frc || (ptr->valid == VALID))
2601556Srgrimes			return(ptr->name);
2611556Srgrimes		return("");
2621556Srgrimes	}
2631556Srgrimes
2641556Srgrimes	/*
2651556Srgrimes	 * No entry for this gid, we will add it
2661556Srgrimes	 */
2671556Srgrimes	if (!gropn) {
2681556Srgrimes		setgroupent(1);
2691556Srgrimes		++gropn;
2701556Srgrimes	}
2711556Srgrimes	if (ptr == NULL)
272127055Scperciva		ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC));
2731556Srgrimes
2741556Srgrimes	if ((gr = getgrgid(gid)) == NULL) {
2751556Srgrimes		/*
2761556Srgrimes		 * no match for this gid in the local group file, put in
27746684Skris		 * a string that is the gid in numeric format
2781556Srgrimes		 */
2791556Srgrimes		if (ptr == NULL)
2801556Srgrimes			return("");
2811556Srgrimes		ptr->gid = gid;
2821556Srgrimes		ptr->valid = INVALID;
2831556Srgrimes#		ifdef NET2_STAT
28476017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
2851556Srgrimes#		else
28676017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
28776017Skris			       (unsigned long)gid);
2881556Srgrimes#		endif
2891556Srgrimes		if (frc == 0)
2901556Srgrimes			return("");
2911556Srgrimes	} else {
2921556Srgrimes		/*
2931556Srgrimes		 * there is an entry for this group in the group file
2941556Srgrimes		 */
2951556Srgrimes		if (ptr == NULL)
2961556Srgrimes			return(gr->gr_name);
2971556Srgrimes		ptr->gid = gid;
29826363Scharnier		(void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
2991556Srgrimes		ptr->name[GNMLEN-1] = '\0';
3001556Srgrimes		ptr->valid = VALID;
3011556Srgrimes	}
3021556Srgrimes	return(ptr->name);
3031556Srgrimes}
3041556Srgrimes
3051556Srgrimes/*
3061556Srgrimes * uid_name()
3071556Srgrimes *	caches the uid for a given user name. We use a simple hash table.
3081556Srgrimes * Return
3091556Srgrimes *	the uid (if any) for a user name, or a -1 if no match can be found
3101556Srgrimes */
3111556Srgrimes
3121556Srgrimesint
3131556Srgrimesuid_name(char *name, uid_t *uid)
3141556Srgrimes{
31590113Simp	struct passwd *pw;
31690113Simp	UIDC *ptr;
31790113Simp	int namelen;
3181556Srgrimes
3191556Srgrimes	/*
3201556Srgrimes	 * return -1 for mangled names
3211556Srgrimes	 */
3221556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3231556Srgrimes		return(-1);
3241556Srgrimes	if ((usrtb == NULL) && (usrtb_start() < 0))
3251556Srgrimes		return(-1);
3261556Srgrimes
3271556Srgrimes	/*
3281556Srgrimes	 * look up in hash table, if found and valid return the uid,
3291556Srgrimes	 * if found and invalid, return a -1
3301556Srgrimes	 */
3311556Srgrimes	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
3321556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3331556Srgrimes		if (ptr->valid == INVALID)
3341556Srgrimes			return(-1);
3351556Srgrimes		*uid = ptr->uid;
3361556Srgrimes		return(0);
3371556Srgrimes	}
3381556Srgrimes
3391556Srgrimes	if (!pwopn) {
3401556Srgrimes		setpassent(1);
3411556Srgrimes		++pwopn;
3421556Srgrimes	}
3431556Srgrimes
3441556Srgrimes	if (ptr == NULL)
34576351Skris		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
34676351Skris		  (UIDC *)malloc(sizeof(UIDC));
3471556Srgrimes
3481556Srgrimes	/*
3491556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
3501556Srgrimes	 * or store the matching uid
3511556Srgrimes	 */
3521556Srgrimes	if (ptr == NULL) {
3531556Srgrimes		if ((pw = getpwnam(name)) == NULL)
3541556Srgrimes			return(-1);
3551556Srgrimes		*uid = pw->pw_uid;
3561556Srgrimes		return(0);
3571556Srgrimes	}
35826363Scharnier	(void)strncpy(ptr->name, name, UNMLEN - 1);
3591556Srgrimes	ptr->name[UNMLEN-1] = '\0';
3601556Srgrimes	if ((pw = getpwnam(name)) == NULL) {
3611556Srgrimes		ptr->valid = INVALID;
3621556Srgrimes		return(-1);
3631556Srgrimes	}
3641556Srgrimes	ptr->valid = VALID;
3651556Srgrimes	*uid = ptr->uid = pw->pw_uid;
3661556Srgrimes	return(0);
3671556Srgrimes}
3681556Srgrimes
3691556Srgrimes/*
3701556Srgrimes * gid_name()
3711556Srgrimes *	caches the gid for a given group name. We use a simple hash table.
3721556Srgrimes * Return
3731556Srgrimes *	the gid (if any) for a group name, or a -1 if no match can be found
3741556Srgrimes */
3751556Srgrimes
3761556Srgrimesint
3771556Srgrimesgid_name(char *name, gid_t *gid)
3781556Srgrimes{
37990113Simp	struct group *gr;
38090113Simp	GIDC *ptr;
38190113Simp	int namelen;
3821556Srgrimes
3831556Srgrimes	/*
3841556Srgrimes	 * return -1 for mangled names
3851556Srgrimes	 */
3861556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3871556Srgrimes		return(-1);
3881556Srgrimes	if ((grptb == NULL) && (grptb_start() < 0))
3891556Srgrimes		return(-1);
3901556Srgrimes
3911556Srgrimes	/*
3921556Srgrimes	 * look up in hash table, if found and valid return the uid,
3931556Srgrimes	 * if found and invalid, return a -1
3941556Srgrimes	 */
3951556Srgrimes	ptr = grptb[st_hash(name, namelen, GID_SZ)];
3961556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3971556Srgrimes		if (ptr->valid == INVALID)
3981556Srgrimes			return(-1);
3991556Srgrimes		*gid = ptr->gid;
4001556Srgrimes		return(0);
4011556Srgrimes	}
4021556Srgrimes
4031556Srgrimes	if (!gropn) {
4041556Srgrimes		setgroupent(1);
4051556Srgrimes		++gropn;
4061556Srgrimes	}
4071556Srgrimes	if (ptr == NULL)
40876351Skris		ptr = grptb[st_hash(name, namelen, GID_SZ)] =
40976351Skris		  (GIDC *)malloc(sizeof(GIDC));
4101556Srgrimes
4111556Srgrimes	/*
4121556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
4131556Srgrimes	 * or store the matching gid
4141556Srgrimes	 */
4151556Srgrimes	if (ptr == NULL) {
4161556Srgrimes		if ((gr = getgrnam(name)) == NULL)
4171556Srgrimes			return(-1);
4181556Srgrimes		*gid = gr->gr_gid;
4191556Srgrimes		return(0);
4201556Srgrimes	}
4211556Srgrimes
42226363Scharnier	(void)strncpy(ptr->name, name, GNMLEN - 1);
4231556Srgrimes	ptr->name[GNMLEN-1] = '\0';
4241556Srgrimes	if ((gr = getgrnam(name)) == NULL) {
4251556Srgrimes		ptr->valid = INVALID;
4261556Srgrimes		return(-1);
4271556Srgrimes	}
4281556Srgrimes	ptr->valid = VALID;
4291556Srgrimes	*gid = ptr->gid = gr->gr_gid;
4301556Srgrimes	return(0);
4311556Srgrimes}
432