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: releng/11.0/bin/pax/cache.c 283257 2015-05-21 18:29:36Z delphij $"); 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