cache.c revision 36049
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[] = 4336049Scharnier "$Id$"; 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 791556Srgrimes#if __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; 9528904Ssos pax_warn(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 1081556Srgrimes#if __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; 12428904Ssos pax_warn(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 1371556Srgrimes#if __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; 15328904Ssos pax_warn(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 1661556Srgrimes#if __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; 18228904Ssos pax_warn(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 1961556Srgrimes#if __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 2381556Srgrimes * a string that is the uid in numberic format 2391556Srgrimes */ 2401556Srgrimes if (ptr == NULL) 2411556Srgrimes return(""); 2421556Srgrimes ptr->uid = uid; 2431556Srgrimes ptr->valid = INVALID; 2441556Srgrimes# ifdef NET2_STAT 2451556Srgrimes (void)sprintf(ptr->name, "%u", uid); 2461556Srgrimes# else 24720420Ssteve (void)sprintf(ptr->name, "%lu", (u_long)uid); 2481556Srgrimes# endif 2491556Srgrimes if (frc == 0) 2501556Srgrimes return(""); 2511556Srgrimes } else { 2521556Srgrimes /* 2531556Srgrimes * there is an entry for this uid in the password file 2541556Srgrimes */ 2551556Srgrimes if (ptr == NULL) 2561556Srgrimes return(pw->pw_name); 2571556Srgrimes ptr->uid = uid; 25826363Scharnier (void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1); 2591556Srgrimes ptr->name[UNMLEN-1] = '\0'; 2601556Srgrimes ptr->valid = VALID; 2611556Srgrimes } 2621556Srgrimes return(ptr->name); 2631556Srgrimes} 2641556Srgrimes 2651556Srgrimes/* 2661556Srgrimes * name_gid() 2671556Srgrimes * caches the name (if any) for the gid. If frc set, we always return the 2681556Srgrimes * the stored name (if valid or invalid match). We use a simple hash table. 2691556Srgrimes * Return 2701556Srgrimes * Pointer to stored name (or a empty string) 2711556Srgrimes */ 2721556Srgrimes 2731556Srgrimes#if __STDC__ 2741556Srgrimeschar * 2751556Srgrimesname_gid(gid_t gid, int frc) 2761556Srgrimes#else 2771556Srgrimeschar * 2781556Srgrimesname_gid(gid, frc) 2791556Srgrimes gid_t gid; 2801556Srgrimes int frc; 2811556Srgrimes#endif 2821556Srgrimes{ 2831556Srgrimes register struct group *gr; 2841556Srgrimes register GIDC *ptr; 2851556Srgrimes 2861556Srgrimes if ((gidtb == NULL) && (gidtb_start() < 0)) 2871556Srgrimes return(""); 2881556Srgrimes 2891556Srgrimes /* 2901556Srgrimes * see if we have this gid cached 2911556Srgrimes */ 2921556Srgrimes ptr = gidtb[gid % GID_SZ]; 2931556Srgrimes if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 2941556Srgrimes /* 2951556Srgrimes * have an entry for this gid 2961556Srgrimes */ 2971556Srgrimes if (frc || (ptr->valid == VALID)) 2981556Srgrimes return(ptr->name); 2991556Srgrimes return(""); 3001556Srgrimes } 3011556Srgrimes 3021556Srgrimes /* 3031556Srgrimes * No entry for this gid, we will add it 3041556Srgrimes */ 3051556Srgrimes if (!gropn) { 3061556Srgrimes setgroupent(1); 3071556Srgrimes ++gropn; 3081556Srgrimes } 3091556Srgrimes if (ptr == NULL) 3101556Srgrimes ptr = (GIDC *)malloc(sizeof(GIDC)); 3111556Srgrimes 3121556Srgrimes if ((gr = getgrgid(gid)) == NULL) { 3131556Srgrimes /* 3141556Srgrimes * no match for this gid in the local group file, put in 3151556Srgrimes * a string that is the gid in numberic format 3161556Srgrimes */ 3171556Srgrimes if (ptr == NULL) 3181556Srgrimes return(""); 3191556Srgrimes ptr->gid = gid; 3201556Srgrimes ptr->valid = INVALID; 3211556Srgrimes# ifdef NET2_STAT 3221556Srgrimes (void)sprintf(ptr->name, "%u", gid); 3231556Srgrimes# else 32420420Ssteve (void)sprintf(ptr->name, "%lu", (u_long)gid); 3251556Srgrimes# endif 3261556Srgrimes if (frc == 0) 3271556Srgrimes return(""); 3281556Srgrimes } else { 3291556Srgrimes /* 3301556Srgrimes * there is an entry for this group in the group file 3311556Srgrimes */ 3321556Srgrimes if (ptr == NULL) 3331556Srgrimes return(gr->gr_name); 3341556Srgrimes ptr->gid = gid; 33526363Scharnier (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1); 3361556Srgrimes ptr->name[GNMLEN-1] = '\0'; 3371556Srgrimes ptr->valid = VALID; 3381556Srgrimes } 3391556Srgrimes return(ptr->name); 3401556Srgrimes} 3411556Srgrimes 3421556Srgrimes/* 3431556Srgrimes * uid_name() 3441556Srgrimes * caches the uid for a given user name. We use a simple hash table. 3451556Srgrimes * Return 3461556Srgrimes * the uid (if any) for a user name, or a -1 if no match can be found 3471556Srgrimes */ 3481556Srgrimes 3491556Srgrimes#if __STDC__ 3501556Srgrimesint 3511556Srgrimesuid_name(char *name, uid_t *uid) 3521556Srgrimes#else 3531556Srgrimesint 3541556Srgrimesuid_name(name, uid) 3551556Srgrimes char *name; 3561556Srgrimes uid_t *uid; 3571556Srgrimes#endif 3581556Srgrimes{ 3591556Srgrimes register struct passwd *pw; 3601556Srgrimes register UIDC *ptr; 3611556Srgrimes register int namelen; 3621556Srgrimes 3631556Srgrimes /* 3641556Srgrimes * return -1 for mangled names 3651556Srgrimes */ 3661556Srgrimes if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 3671556Srgrimes return(-1); 3681556Srgrimes if ((usrtb == NULL) && (usrtb_start() < 0)) 3691556Srgrimes return(-1); 3701556Srgrimes 3711556Srgrimes /* 3721556Srgrimes * look up in hash table, if found and valid return the uid, 3731556Srgrimes * if found and invalid, return a -1 3741556Srgrimes */ 3751556Srgrimes ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 3761556Srgrimes if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 3771556Srgrimes if (ptr->valid == INVALID) 3781556Srgrimes return(-1); 3791556Srgrimes *uid = ptr->uid; 3801556Srgrimes return(0); 3811556Srgrimes } 3821556Srgrimes 3831556Srgrimes if (!pwopn) { 3841556Srgrimes setpassent(1); 3851556Srgrimes ++pwopn; 3861556Srgrimes } 3871556Srgrimes 3881556Srgrimes if (ptr == NULL) 3891556Srgrimes ptr = (UIDC *)malloc(sizeof(UIDC)); 3901556Srgrimes 3911556Srgrimes /* 3921556Srgrimes * no match, look it up, if no match store it as an invalid entry, 3931556Srgrimes * or store the matching uid 3941556Srgrimes */ 3951556Srgrimes if (ptr == NULL) { 3961556Srgrimes if ((pw = getpwnam(name)) == NULL) 3971556Srgrimes return(-1); 3981556Srgrimes *uid = pw->pw_uid; 3991556Srgrimes return(0); 4001556Srgrimes } 40126363Scharnier (void)strncpy(ptr->name, name, UNMLEN - 1); 4021556Srgrimes ptr->name[UNMLEN-1] = '\0'; 4031556Srgrimes if ((pw = getpwnam(name)) == NULL) { 4041556Srgrimes ptr->valid = INVALID; 4051556Srgrimes return(-1); 4061556Srgrimes } 4071556Srgrimes ptr->valid = VALID; 4081556Srgrimes *uid = ptr->uid = pw->pw_uid; 4091556Srgrimes return(0); 4101556Srgrimes} 4111556Srgrimes 4121556Srgrimes/* 4131556Srgrimes * gid_name() 4141556Srgrimes * caches the gid for a given group name. We use a simple hash table. 4151556Srgrimes * Return 4161556Srgrimes * the gid (if any) for a group name, or a -1 if no match can be found 4171556Srgrimes */ 4181556Srgrimes 4191556Srgrimes#if __STDC__ 4201556Srgrimesint 4211556Srgrimesgid_name(char *name, gid_t *gid) 4221556Srgrimes#else 4231556Srgrimesint 4241556Srgrimesgid_name(name, gid) 4251556Srgrimes char *name; 4261556Srgrimes gid_t *gid; 4271556Srgrimes#endif 4281556Srgrimes{ 4291556Srgrimes register struct group *gr; 4301556Srgrimes register GIDC *ptr; 4311556Srgrimes register int namelen; 4321556Srgrimes 4331556Srgrimes /* 4341556Srgrimes * return -1 for mangled names 4351556Srgrimes */ 4361556Srgrimes if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 4371556Srgrimes return(-1); 4381556Srgrimes if ((grptb == NULL) && (grptb_start() < 0)) 4391556Srgrimes return(-1); 4401556Srgrimes 4411556Srgrimes /* 4421556Srgrimes * look up in hash table, if found and valid return the uid, 4431556Srgrimes * if found and invalid, return a -1 4441556Srgrimes */ 4451556Srgrimes ptr = grptb[st_hash(name, namelen, GID_SZ)]; 4461556Srgrimes if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 4471556Srgrimes if (ptr->valid == INVALID) 4481556Srgrimes return(-1); 4491556Srgrimes *gid = ptr->gid; 4501556Srgrimes return(0); 4511556Srgrimes } 4521556Srgrimes 4531556Srgrimes if (!gropn) { 4541556Srgrimes setgroupent(1); 4551556Srgrimes ++gropn; 4561556Srgrimes } 4571556Srgrimes if (ptr == NULL) 4581556Srgrimes ptr = (GIDC *)malloc(sizeof(GIDC)); 4591556Srgrimes 4601556Srgrimes /* 4611556Srgrimes * no match, look it up, if no match store it as an invalid entry, 4621556Srgrimes * or store the matching gid 4631556Srgrimes */ 4641556Srgrimes if (ptr == NULL) { 4651556Srgrimes if ((gr = getgrnam(name)) == NULL) 4661556Srgrimes return(-1); 4671556Srgrimes *gid = gr->gr_gid; 4681556Srgrimes return(0); 4691556Srgrimes } 4701556Srgrimes 47126363Scharnier (void)strncpy(ptr->name, name, GNMLEN - 1); 4721556Srgrimes ptr->name[GNMLEN-1] = '\0'; 4731556Srgrimes if ((gr = getgrnam(name)) == NULL) { 4741556Srgrimes ptr->valid = INVALID; 4751556Srgrimes return(-1); 4761556Srgrimes } 4771556Srgrimes ptr->valid = VALID; 4781556Srgrimes *gid = ptr->gid = gr->gr_gid; 4791556Srgrimes return(0); 4801556Srgrimes} 481