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