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