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 <unistd.h>
491556Srgrimes#include <stdlib.h>
501556Srgrimes#include "pax.h"
511556Srgrimes#include "cache.h"
521556Srgrimes#include "extern.h"
531556Srgrimes
541556Srgrimes/*
551556Srgrimes * routines that control user, group, uid and gid caches (for the archive
561556Srgrimes * member print routine).
571556Srgrimes * IMPORTANT:
581556Srgrimes * these routines cache BOTH hits and misses, a major performance improvement
591556Srgrimes */
601556Srgrimes
611556Srgrimesstatic	int pwopn = 0;		/* is password file open */
621556Srgrimesstatic	int gropn = 0;		/* is group file open */
631556Srgrimesstatic UIDC **uidtb = NULL;	/* uid to name cache */
641556Srgrimesstatic GIDC **gidtb = NULL;	/* gid to name cache */
651556Srgrimesstatic UIDC **usrtb = NULL;	/* user name to uid cache */
661556Srgrimesstatic GIDC **grptb = NULL;	/* group name to gid cache */
671556Srgrimes
681556Srgrimes/*
691556Srgrimes * uidtb_start
701556Srgrimes *	creates an an empty uidtb
711556Srgrimes * Return:
721556Srgrimes *	0 if ok, -1 otherwise
731556Srgrimes */
741556Srgrimes
751556Srgrimesint
761556Srgrimesuidtb_start(void)
771556Srgrimes{
781556Srgrimes	static int fail = 0;
791556Srgrimes
801556Srgrimes	if (uidtb != NULL)
811556Srgrimes		return(0);
821556Srgrimes	if (fail)
831556Srgrimes		return(-1);
841556Srgrimes	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
851556Srgrimes		++fail;
8676017Skris		paxwarn(1, "Unable to allocate memory for user id cache table");
871556Srgrimes		return(-1);
881556Srgrimes	}
891556Srgrimes	return(0);
901556Srgrimes}
911556Srgrimes
921556Srgrimes/*
931556Srgrimes * gidtb_start
941556Srgrimes *	creates an an empty gidtb
951556Srgrimes * Return:
961556Srgrimes *	0 if ok, -1 otherwise
971556Srgrimes */
981556Srgrimes
991556Srgrimesint
1001556Srgrimesgidtb_start(void)
1011556Srgrimes{
1021556Srgrimes	static int fail = 0;
1031556Srgrimes
1041556Srgrimes	if (gidtb != NULL)
1051556Srgrimes		return(0);
1061556Srgrimes	if (fail)
1071556Srgrimes		return(-1);
1081556Srgrimes	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
1091556Srgrimes		++fail;
11076017Skris		paxwarn(1, "Unable to allocate memory for group id cache table");
1111556Srgrimes		return(-1);
1121556Srgrimes	}
1131556Srgrimes	return(0);
1141556Srgrimes}
1151556Srgrimes
1161556Srgrimes/*
1171556Srgrimes * usrtb_start
1181556Srgrimes *	creates an an empty usrtb
1191556Srgrimes * Return:
1201556Srgrimes *	0 if ok, -1 otherwise
1211556Srgrimes */
1221556Srgrimes
1231556Srgrimesint
1241556Srgrimesusrtb_start(void)
1251556Srgrimes{
1261556Srgrimes	static int fail = 0;
1271556Srgrimes
1281556Srgrimes	if (usrtb != NULL)
1291556Srgrimes		return(0);
1301556Srgrimes	if (fail)
1311556Srgrimes		return(-1);
1321556Srgrimes	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
1331556Srgrimes		++fail;
13476017Skris		paxwarn(1, "Unable to allocate memory for user name cache table");
1351556Srgrimes		return(-1);
1361556Srgrimes	}
1371556Srgrimes	return(0);
1381556Srgrimes}
1391556Srgrimes
1401556Srgrimes/*
1411556Srgrimes * grptb_start
1421556Srgrimes *	creates an an empty grptb
1431556Srgrimes * Return:
1441556Srgrimes *	0 if ok, -1 otherwise
1451556Srgrimes */
1461556Srgrimes
1471556Srgrimesint
1481556Srgrimesgrptb_start(void)
1491556Srgrimes{
1501556Srgrimes	static int fail = 0;
1511556Srgrimes
1521556Srgrimes	if (grptb != NULL)
1531556Srgrimes		return(0);
1541556Srgrimes	if (fail)
1551556Srgrimes		return(-1);
1561556Srgrimes	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
1571556Srgrimes		++fail;
15876017Skris		paxwarn(1,"Unable to allocate memory for group name cache table");
1591556Srgrimes		return(-1);
1601556Srgrimes	}
1611556Srgrimes	return(0);
1621556Srgrimes}
1631556Srgrimes
1641556Srgrimes/*
1651556Srgrimes * name_uid()
1661556Srgrimes *	caches the name (if any) for the uid. If frc set, we always return the
1671556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
1681556Srgrimes * Return
169108533Sschweikh *	Pointer to stored name (or an empty string).
1701556Srgrimes */
1711556Srgrimes
172114583Smarkmconst char *
1731556Srgrimesname_uid(uid_t uid, int frc)
1741556Srgrimes{
17590113Simp	struct passwd *pw;
17690113Simp	UIDC *ptr;
1771556Srgrimes
1781556Srgrimes	if ((uidtb == NULL) && (uidtb_start() < 0))
1791556Srgrimes		return("");
1801556Srgrimes
1811556Srgrimes	/*
1821556Srgrimes	 * see if we have this uid cached
1831556Srgrimes	 */
1841556Srgrimes	ptr = uidtb[uid % UID_SZ];
1851556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
1861556Srgrimes		/*
1871556Srgrimes		 * have an entry for this uid
1881556Srgrimes		 */
1891556Srgrimes		if (frc || (ptr->valid == VALID))
1901556Srgrimes			return(ptr->name);
1911556Srgrimes		return("");
1921556Srgrimes	}
1931556Srgrimes
1941556Srgrimes	/*
1951556Srgrimes	 * No entry for this uid, we will add it
1961556Srgrimes	 */
1971556Srgrimes	if (!pwopn) {
1981556Srgrimes		setpassent(1);
1991556Srgrimes		++pwopn;
2001556Srgrimes	}
2011556Srgrimes	if (ptr == NULL)
202127055Scperciva		ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC));
2031556Srgrimes
2041556Srgrimes	if ((pw = getpwuid(uid)) == NULL) {
2051556Srgrimes		/*
2061556Srgrimes		 * no match for this uid in the local password file
20746684Skris		 * a string that is the uid in numeric format
2081556Srgrimes		 */
2091556Srgrimes		if (ptr == NULL)
2101556Srgrimes			return("");
2111556Srgrimes		ptr->uid = uid;
2121556Srgrimes		ptr->valid = INVALID;
2131556Srgrimes#		ifdef NET2_STAT
21476017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
2151556Srgrimes#		else
21676017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
21776017Skris			       (unsigned long)uid);
2181556Srgrimes#		endif
2191556Srgrimes		if (frc == 0)
2201556Srgrimes			return("");
2211556Srgrimes	} else {
2221556Srgrimes		/*
2231556Srgrimes		 * there is an entry for this uid in the password file
2241556Srgrimes		 */
2251556Srgrimes		if (ptr == NULL)
2261556Srgrimes			return(pw->pw_name);
2271556Srgrimes		ptr->uid = uid;
22826363Scharnier		(void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
2291556Srgrimes		ptr->name[UNMLEN-1] = '\0';
2301556Srgrimes		ptr->valid = VALID;
2311556Srgrimes	}
2321556Srgrimes	return(ptr->name);
2331556Srgrimes}
2341556Srgrimes
2351556Srgrimes/*
2361556Srgrimes * name_gid()
2371556Srgrimes *	caches the name (if any) for the gid. If frc set, we always return the
2381556Srgrimes *	the stored name (if valid or invalid match). We use a simple hash table.
2391556Srgrimes * Return
240108533Sschweikh *	Pointer to stored name (or an empty string).
2411556Srgrimes */
2421556Srgrimes
243114583Smarkmconst char *
2441556Srgrimesname_gid(gid_t gid, int frc)
2451556Srgrimes{
24690113Simp	struct group *gr;
24790113Simp	GIDC *ptr;
2481556Srgrimes
2491556Srgrimes	if ((gidtb == NULL) && (gidtb_start() < 0))
2501556Srgrimes		return("");
2511556Srgrimes
2521556Srgrimes	/*
2531556Srgrimes	 * see if we have this gid cached
2541556Srgrimes	 */
2551556Srgrimes	ptr = gidtb[gid % GID_SZ];
2561556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
2571556Srgrimes		/*
2581556Srgrimes		 * have an entry for this gid
2591556Srgrimes		 */
2601556Srgrimes		if (frc || (ptr->valid == VALID))
2611556Srgrimes			return(ptr->name);
2621556Srgrimes		return("");
2631556Srgrimes	}
2641556Srgrimes
2651556Srgrimes	/*
2661556Srgrimes	 * No entry for this gid, we will add it
2671556Srgrimes	 */
2681556Srgrimes	if (!gropn) {
2691556Srgrimes		setgroupent(1);
2701556Srgrimes		++gropn;
2711556Srgrimes	}
2721556Srgrimes	if (ptr == NULL)
273127055Scperciva		ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC));
2741556Srgrimes
2751556Srgrimes	if ((gr = getgrgid(gid)) == NULL) {
2761556Srgrimes		/*
2771556Srgrimes		 * no match for this gid in the local group file, put in
27846684Skris		 * a string that is the gid in numeric format
2791556Srgrimes		 */
2801556Srgrimes		if (ptr == NULL)
2811556Srgrimes			return("");
2821556Srgrimes		ptr->gid = gid;
2831556Srgrimes		ptr->valid = INVALID;
2841556Srgrimes#		ifdef NET2_STAT
28576017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
2861556Srgrimes#		else
28776017Skris		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
28876017Skris			       (unsigned long)gid);
2891556Srgrimes#		endif
2901556Srgrimes		if (frc == 0)
2911556Srgrimes			return("");
2921556Srgrimes	} else {
2931556Srgrimes		/*
2941556Srgrimes		 * there is an entry for this group in the group file
2951556Srgrimes		 */
2961556Srgrimes		if (ptr == NULL)
2971556Srgrimes			return(gr->gr_name);
2981556Srgrimes		ptr->gid = gid;
29926363Scharnier		(void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
3001556Srgrimes		ptr->name[GNMLEN-1] = '\0';
3011556Srgrimes		ptr->valid = VALID;
3021556Srgrimes	}
3031556Srgrimes	return(ptr->name);
3041556Srgrimes}
3051556Srgrimes
3061556Srgrimes/*
3071556Srgrimes * uid_name()
3081556Srgrimes *	caches the uid for a given user name. We use a simple hash table.
3091556Srgrimes * Return
3101556Srgrimes *	the uid (if any) for a user name, or a -1 if no match can be found
3111556Srgrimes */
3121556Srgrimes
3131556Srgrimesint
3141556Srgrimesuid_name(char *name, uid_t *uid)
3151556Srgrimes{
31690113Simp	struct passwd *pw;
31790113Simp	UIDC *ptr;
31890113Simp	int namelen;
3191556Srgrimes
3201556Srgrimes	/*
3211556Srgrimes	 * return -1 for mangled names
3221556Srgrimes	 */
3231556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3241556Srgrimes		return(-1);
3251556Srgrimes	if ((usrtb == NULL) && (usrtb_start() < 0))
3261556Srgrimes		return(-1);
3271556Srgrimes
3281556Srgrimes	/*
3291556Srgrimes	 * look up in hash table, if found and valid return the uid,
3301556Srgrimes	 * if found and invalid, return a -1
3311556Srgrimes	 */
3321556Srgrimes	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
3331556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3341556Srgrimes		if (ptr->valid == INVALID)
3351556Srgrimes			return(-1);
3361556Srgrimes		*uid = ptr->uid;
3371556Srgrimes		return(0);
3381556Srgrimes	}
3391556Srgrimes
3401556Srgrimes	if (!pwopn) {
3411556Srgrimes		setpassent(1);
3421556Srgrimes		++pwopn;
3431556Srgrimes	}
3441556Srgrimes
3451556Srgrimes	if (ptr == NULL)
34676351Skris		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
34776351Skris		  (UIDC *)malloc(sizeof(UIDC));
3481556Srgrimes
3491556Srgrimes	/*
3501556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
3511556Srgrimes	 * or store the matching uid
3521556Srgrimes	 */
3531556Srgrimes	if (ptr == NULL) {
3541556Srgrimes		if ((pw = getpwnam(name)) == NULL)
3551556Srgrimes			return(-1);
3561556Srgrimes		*uid = pw->pw_uid;
3571556Srgrimes		return(0);
3581556Srgrimes	}
35926363Scharnier	(void)strncpy(ptr->name, name, UNMLEN - 1);
3601556Srgrimes	ptr->name[UNMLEN-1] = '\0';
3611556Srgrimes	if ((pw = getpwnam(name)) == NULL) {
3621556Srgrimes		ptr->valid = INVALID;
3631556Srgrimes		return(-1);
3641556Srgrimes	}
3651556Srgrimes	ptr->valid = VALID;
3661556Srgrimes	*uid = ptr->uid = pw->pw_uid;
3671556Srgrimes	return(0);
3681556Srgrimes}
3691556Srgrimes
3701556Srgrimes/*
3711556Srgrimes * gid_name()
3721556Srgrimes *	caches the gid for a given group name. We use a simple hash table.
3731556Srgrimes * Return
3741556Srgrimes *	the gid (if any) for a group name, or a -1 if no match can be found
3751556Srgrimes */
3761556Srgrimes
3771556Srgrimesint
3781556Srgrimesgid_name(char *name, gid_t *gid)
3791556Srgrimes{
38090113Simp	struct group *gr;
38190113Simp	GIDC *ptr;
38290113Simp	int namelen;
3831556Srgrimes
3841556Srgrimes	/*
3851556Srgrimes	 * return -1 for mangled names
3861556Srgrimes	 */
3871556Srgrimes	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
3881556Srgrimes		return(-1);
3891556Srgrimes	if ((grptb == NULL) && (grptb_start() < 0))
3901556Srgrimes		return(-1);
3911556Srgrimes
3921556Srgrimes	/*
3931556Srgrimes	 * look up in hash table, if found and valid return the uid,
3941556Srgrimes	 * if found and invalid, return a -1
3951556Srgrimes	 */
3961556Srgrimes	ptr = grptb[st_hash(name, namelen, GID_SZ)];
3971556Srgrimes	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
3981556Srgrimes		if (ptr->valid == INVALID)
3991556Srgrimes			return(-1);
4001556Srgrimes		*gid = ptr->gid;
4011556Srgrimes		return(0);
4021556Srgrimes	}
4031556Srgrimes
4041556Srgrimes	if (!gropn) {
4051556Srgrimes		setgroupent(1);
4061556Srgrimes		++gropn;
4071556Srgrimes	}
4081556Srgrimes	if (ptr == NULL)
40976351Skris		ptr = grptb[st_hash(name, namelen, GID_SZ)] =
41076351Skris		  (GIDC *)malloc(sizeof(GIDC));
4111556Srgrimes
4121556Srgrimes	/*
4131556Srgrimes	 * no match, look it up, if no match store it as an invalid entry,
4141556Srgrimes	 * or store the matching gid
4151556Srgrimes	 */
4161556Srgrimes	if (ptr == NULL) {
4171556Srgrimes		if ((gr = getgrnam(name)) == NULL)
4181556Srgrimes			return(-1);
4191556Srgrimes		*gid = gr->gr_gid;
4201556Srgrimes		return(0);
4211556Srgrimes	}
4221556Srgrimes
42326363Scharnier	(void)strncpy(ptr->name, name, GNMLEN - 1);
4241556Srgrimes	ptr->name[GNMLEN-1] = '\0';
4251556Srgrimes	if ((gr = getgrnam(name)) == NULL) {
4261556Srgrimes		ptr->valid = INVALID;
4271556Srgrimes		return(-1);
4281556Srgrimes	}
4291556Srgrimes	ptr->valid = VALID;
4301556Srgrimes	*gid = ptr->gid = gr->gr_gid;
4311556Srgrimes	return(0);
4321556Srgrimes}
433