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