cache.c revision 127055
121308Sache/*- 221308Sache * Copyright (c) 1992 Keith Muller. 321308Sache * Copyright (c) 1992, 1993 421308Sache * The Regents of the University of California. All rights reserved. 521308Sache * 621308Sache * This code is derived from software contributed to Berkeley by 7157184Sache * Keith Muller of the University of California, San Diego. 821308Sache * 921308Sache * Redistribution and use in source and binary forms, with or without 1021308Sache * modification, are permitted provided that the following conditions 1121308Sache * are met: 1221308Sache * 1. Redistributions of source code must retain the above copyright 1321308Sache * notice, this list of conditions and the following disclaimer. 1421308Sache * 2. Redistributions in binary form must reproduce the above copyright 1558310Sache * notice, this list of conditions and the following disclaimer in the 1621308Sache * documentation and/or other materials provided with the distribution. 1721308Sache * 3. All advertising materials mentioning features or use of this software 1821308Sache * must display the following acknowledgement: 1921308Sache * This product includes software developed by the University of 2021308Sache * California, Berkeley and its contributors. 2121308Sache * 4. Neither the name of the University nor the names of its contributors 2221308Sache * may be used to endorse or promote products derived from this software 2321308Sache * without specific prior written permission. 2421308Sache * 2521308Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2658310Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2721308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2821308Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2921308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3021308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3121308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3221308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3326497Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3426497Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3521308Sache * SUCH DAMAGE. 3621308Sache */ 3721308Sache 3821308Sache#ifndef lint 3921308Sache#if 0 4021308Sachestatic char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; 4126497Sache#endif 4226497Sache#endif /* not lint */ 4326497Sache#include <sys/cdefs.h> 4426497Sache__FBSDID("$FreeBSD: head/bin/pax/cache.c 127055 2004-03-16 08:33:33Z cperciva $"); 4526497Sache 4621308Sache#include <sys/types.h> 4721308Sache#include <sys/stat.h> 48119610Sache#include <string.h> 49119610Sache#include <stdio.h> 5021308Sache#include <pwd.h> 5121308Sache#include <grp.h> 5221308Sache#include <unistd.h> 5358310Sache#include <stdlib.h> 5458310Sache#include "pax.h" 5558310Sache#include "cache.h" 5647558Sache#include "extern.h" 57119610Sache 5847558Sache/* 59157184Sache * routines that control user, group, uid and gid caches (for the archive 60157184Sache * member print routine). 6121308Sache * IMPORTANT: 6275406Sache * these routines cache BOTH hits and misses, a major performance improvement 6321308Sache */ 64119610Sache 6521308Sachestatic int pwopn = 0; /* is password file open */ 66157184Sachestatic int gropn = 0; /* is group file open */ 67157184Sachestatic UIDC **uidtb = NULL; /* uid to name cache */ 68157184Sachestatic GIDC **gidtb = NULL; /* gid to name cache */ 69157184Sachestatic UIDC **usrtb = NULL; /* user name to uid cache */ 7021308Sachestatic GIDC **grptb = NULL; /* group name to gid cache */ 71165670Sache 72165670Sache/* 7321308Sache * uidtb_start 74119610Sache * creates an an empty uidtb 75119610Sache * Return: 76119610Sache * 0 if ok, -1 otherwise 7775406Sache */ 78119610Sache 79119610Sacheint 80157184Sacheuidtb_start(void) 81157184Sache{ 82157184Sache static int fail = 0; 83157184Sache 84157184Sache if (uidtb != NULL) 85157184Sache return(0); 86157184Sache if (fail) 87157184Sache return(-1); 88157184Sache if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 89157184Sache ++fail; 90157184Sache paxwarn(1, "Unable to allocate memory for user id cache table"); 91157184Sache return(-1); 92157184Sache } 93157184Sache return(0); 94157184Sache} 95157184Sache 96157184Sache/* 97157184Sache * gidtb_start 98157184Sache * creates an an empty gidtb 99157184Sache * Return: 100157184Sache * 0 if ok, -1 otherwise 101157184Sache */ 102157184Sache 103157184Sacheint 104157184Sachegidtb_start(void) 105157184Sache{ 106157184Sache static int fail = 0; 107157184Sache 108157184Sache if (gidtb != NULL) 109157184Sache return(0); 110157184Sache if (fail) 111157184Sache return(-1); 112157184Sache if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 113157184Sache ++fail; 114157184Sache paxwarn(1, "Unable to allocate memory for group id cache table"); 115157184Sache return(-1); 116157184Sache } 117157184Sache return(0); 118157184Sache} 119157184Sache 120157184Sache/* 121157184Sache * usrtb_start 122157184Sache * creates an an empty usrtb 123157184Sache * Return: 124157184Sache * 0 if ok, -1 otherwise 125157184Sache */ 126157184Sache 127157184Sacheint 128157184Sacheusrtb_start(void) 129157184Sache{ 130157184Sache static int fail = 0; 13121308Sache 13221308Sache if (usrtb != NULL) 13321308Sache return(0); 13421308Sache if (fail) 13521308Sache return(-1); 13621308Sache if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 13721308Sache ++fail; 13821308Sache paxwarn(1, "Unable to allocate memory for user name cache table"); 13921308Sache return(-1); 14021308Sache } 14121308Sache return(0); 14221308Sache} 14321308Sache 14421308Sache/* 14521308Sache * grptb_start 14621308Sache * creates an an empty grptb 14721308Sache * Return: 14821308Sache * 0 if ok, -1 otherwise 14921308Sache */ 15021308Sache 151157184Sacheint 15221308Sachegrptb_start(void) 15321308Sache{ 15421308Sache static int fail = 0; 15521308Sache 15621308Sache if (grptb != NULL) 15721308Sache return(0); 15821308Sache if (fail) 15921308Sache return(-1); 16021308Sache if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 16121308Sache ++fail; 16221308Sache paxwarn(1,"Unable to allocate memory for group name cache table"); 16321308Sache return(-1); 164119610Sache } 16521308Sache return(0); 16621308Sache} 16721308Sache 16821308Sache/* 16921308Sache * name_uid() 17021308Sache * caches the name (if any) for the uid. If frc set, we always return the 17121308Sache * the stored name (if valid or invalid match). We use a simple hash table. 17221308Sache * Return 17321308Sache * Pointer to stored name (or an empty string). 17421308Sache */ 17521308Sache 17621308Sacheconst char * 17721308Sachename_uid(uid_t uid, int frc) 17821308Sache{ 17921308Sache struct passwd *pw; 18021308Sache UIDC *ptr; 18121308Sache 18221308Sache if ((uidtb == NULL) && (uidtb_start() < 0)) 18321308Sache return(""); 18421308Sache 18521308Sache /* 18621308Sache * see if we have this uid cached 18721308Sache */ 18821308Sache ptr = uidtb[uid % UID_SZ]; 18921308Sache if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { 19021308Sache /* 19121308Sache * have an entry for this uid 19221308Sache */ 19321308Sache if (frc || (ptr->valid == VALID)) 194119610Sache return(ptr->name); 19521308Sache return(""); 19621308Sache } 19721308Sache 19821308Sache /* 199157184Sache * No entry for this uid, we will add it 200157184Sache */ 201157184Sache if (!pwopn) { 20221308Sache setpassent(1); 203157184Sache ++pwopn; 204157184Sache } 20521308Sache if (ptr == NULL) 20621308Sache ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC)); 207157184Sache 208157184Sache if ((pw = getpwuid(uid)) == NULL) { 209157184Sache /* 21021308Sache * no match for this uid in the local password file 211157184Sache * a string that is the uid in numeric format 21275406Sache */ 21347558Sache if (ptr == NULL) 21421308Sache return(""); 215157184Sache ptr->uid = uid; 21675406Sache ptr->valid = INVALID; 21721308Sache# ifdef NET2_STAT 21821308Sache (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid); 21921308Sache# else 22021308Sache (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", 22121308Sache (unsigned long)uid); 22221308Sache# endif 223157184Sache if (frc == 0) 224157184Sache return(""); 225157184Sache } else { 22621308Sache /* 22775406Sache * there is an entry for this uid in the password file 228157184Sache */ 22921308Sache if (ptr == NULL) 23021308Sache return(pw->pw_name); 23121308Sache ptr->uid = uid; 232157184Sache (void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1); 233157184Sache ptr->name[UNMLEN-1] = '\0'; 234157184Sache ptr->valid = VALID; 23521308Sache } 23621308Sache return(ptr->name); 237157184Sache} 23821308Sache 23921308Sache/* 240157184Sache * name_gid() 24121308Sache * caches the name (if any) for the gid. If frc set, we always return the 24247558Sache * the stored name (if valid or invalid match). We use a simple hash table. 24321308Sache * Return 24421308Sache * Pointer to stored name (or an empty string). 245157184Sache */ 246157184Sache 24721308Sacheconst char * 24821308Sachename_gid(gid_t gid, int frc) 249157184Sache{ 25021308Sache struct group *gr; 251157184Sache GIDC *ptr; 252157184Sache 253157184Sache if ((gidtb == NULL) && (gidtb_start() < 0)) 25421308Sache return(""); 255157184Sache 25621308Sache /* 257157184Sache * see if we have this gid cached 258157184Sache */ 259157184Sache ptr = gidtb[gid % GID_SZ]; 260157184Sache if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 261157184Sache /* 262157184Sache * have an entry for this gid 263157184Sache */ 264157184Sache if (frc || (ptr->valid == VALID)) 265157184Sache return(ptr->name); 266157184Sache return(""); 267157184Sache } 268157184Sache 269157184Sache /* 270157184Sache * No entry for this gid, we will add it 271157184Sache */ 272157184Sache if (!gropn) { 273157184Sache setgroupent(1); 274157184Sache ++gropn; 275157184Sache } 276157184Sache if (ptr == NULL) 277157184Sache ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC)); 278157184Sache 279157184Sache if ((gr = getgrgid(gid)) == NULL) { 280157184Sache /* 281157184Sache * no match for this gid in the local group file, put in 282157184Sache * a string that is the gid in numeric format 283157184Sache */ 28421308Sache if (ptr == NULL) 285157184Sache return(""); 286157184Sache ptr->gid = gid; 287157184Sache ptr->valid = INVALID; 288157184Sache# ifdef NET2_STAT 289157184Sache (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid); 290157184Sache# else 29121308Sache (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", 292157184Sache (unsigned long)gid); 293157184Sache# endif 294157184Sache if (frc == 0) 29521308Sache return(""); 296157184Sache } else { 297157184Sache /* 298157184Sache * there is an entry for this group in the group file 299157184Sache */ 300157184Sache if (ptr == NULL) 301157184Sache return(gr->gr_name); 302157184Sache ptr->gid = gid; 303157184Sache (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1); 304157184Sache ptr->name[GNMLEN-1] = '\0'; 305157184Sache ptr->valid = VALID; 306157184Sache } 307157184Sache return(ptr->name); 308157184Sache} 309157184Sache 310119610Sache/* 311157184Sache * uid_name() 312157184Sache * caches the uid for a given user name. We use a simple hash table. 313119610Sache * Return 314119610Sache * the uid (if any) for a user name, or a -1 if no match can be found 315157184Sache */ 316157184Sache 31721308Sacheint 318157184Sacheuid_name(char *name, uid_t *uid) 319157184Sache{ 320157184Sache struct passwd *pw; 321157184Sache UIDC *ptr; 322157184Sache int namelen; 323157184Sache 324157184Sache /* 325157184Sache * return -1 for mangled names 326157184Sache */ 327157184Sache if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 32821308Sache return(-1); 329157184Sache if ((usrtb == NULL) && (usrtb_start() < 0)) 330173403Sache return(-1); 331173403Sache 332173403Sache /* 333173403Sache * look up in hash table, if found and valid return the uid, 334173403Sache * if found and invalid, return a -1 335173403Sache */ 336173403Sache ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 337173403Sache if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 338173403Sache if (ptr->valid == INVALID) 339157184Sache return(-1); 340157184Sache *uid = ptr->uid; 341157184Sache return(0); 34221308Sache } 343157184Sache 344157184Sache if (!pwopn) { 345157184Sache setpassent(1); 346157184Sache ++pwopn; 347157184Sache } 348157184Sache 349157184Sache if (ptr == NULL) 350157184Sache ptr = usrtb[st_hash(name, namelen, UNM_SZ)] = 351157184Sache (UIDC *)malloc(sizeof(UIDC)); 352157184Sache 353157184Sache /* 354157184Sache * no match, look it up, if no match store it as an invalid entry, 355157184Sache * or store the matching uid 356157184Sache */ 357157184Sache if (ptr == NULL) { 358157184Sache if ((pw = getpwnam(name)) == NULL) 359157184Sache return(-1); 360157184Sache *uid = pw->pw_uid; 361157184Sache return(0); 362157184Sache } 363157184Sache (void)strncpy(ptr->name, name, UNMLEN - 1); 364157184Sache ptr->name[UNMLEN-1] = '\0'; 365157184Sache if ((pw = getpwnam(name)) == NULL) { 366157184Sache ptr->valid = INVALID; 367157184Sache return(-1); 368157184Sache } 369157184Sache ptr->valid = VALID; 370157184Sache *uid = ptr->uid = pw->pw_uid; 371157184Sache return(0); 372157184Sache} 373157184Sache 374157184Sache/* 375157184Sache * gid_name() 376157184Sache * caches the gid for a given group name. We use a simple hash table. 377119610Sache * Return 378119610Sache * the gid (if any) for a group name, or a -1 if no match can be found 379119610Sache */ 380119610Sache 381157184Sacheint 382157184Sachegid_name(char *name, gid_t *gid) 383157184Sache{ 38421308Sache struct group *gr; 38575406Sache GIDC *ptr; 38675406Sache int namelen; 387157184Sache 388157184Sache /* 38921308Sache * return -1 for mangled names 390157184Sache */ 391157184Sache if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 392157184Sache return(-1); 393157184Sache if ((grptb == NULL) && (grptb_start() < 0)) 394157184Sache return(-1); 395157184Sache 396157184Sache /* 397157184Sache * look up in hash table, if found and valid return the uid, 398157184Sache * if found and invalid, return a -1 399157184Sache */ 40021308Sache ptr = grptb[st_hash(name, namelen, GID_SZ)]; 401157184Sache if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 402157184Sache if (ptr->valid == INVALID) 403157184Sache return(-1); 404157184Sache *gid = ptr->gid; 405157184Sache return(0); 406157184Sache } 407157184Sache 40821308Sache if (!gropn) { 409157184Sache setgroupent(1); 410119610Sache ++gropn; 411157184Sache } 412157184Sache if (ptr == NULL) 413157184Sache ptr = grptb[st_hash(name, namelen, GID_SZ)] = 414157184Sache (GIDC *)malloc(sizeof(GIDC)); 415157184Sache 416157184Sache /* 417119610Sache * no match, look it up, if no match store it as an invalid entry, 418157184Sache * or store the matching gid 419157184Sache */ 420157184Sache if (ptr == NULL) { 421157184Sache if ((gr = getgrnam(name)) == NULL) 422157184Sache return(-1); 423157184Sache *gid = gr->gr_gid; 424157184Sache return(0); 425157184Sache } 426157184Sache 42721308Sache (void)strncpy(ptr->name, name, GNMLEN - 1); 428157184Sache ptr->name[GNMLEN-1] = '\0'; 429157184Sache if ((gr = getgrnam(name)) == NULL) { 430157184Sache ptr->valid = INVALID; 431157184Sache return(-1); 432157184Sache } 433157184Sache ptr->valid = VALID; 434157184Sache *gid = ptr->gid = gr->gr_gid; 435157184Sache return(0); 43621308Sache} 437157184Sache