1*57194Smuller /*- 2*57194Smuller * Copyright (c) 1992 Keith Muller. 3*57194Smuller * Copyright (c) 1992 The Regents of the University of California. 4*57194Smuller * All rights reserved. 5*57194Smuller * 6*57194Smuller * This code is derived from software contributed to Berkeley by 7*57194Smuller * Keith Muller of the University of California, San Diego. 8*57194Smuller * 9*57194Smuller * %sccs.include.redist.c% 10*57194Smuller */ 11*57194Smuller 12*57194Smuller #ifndef lint 13*57194Smuller static char sccsid[] = "@(#)cache.c 1.1 (Berkeley) 12/17/92"; 14*57194Smuller #endif /* not lint */ 15*57194Smuller 16*57194Smuller #include <sys/types.h> 17*57194Smuller #include <sys/time.h> 18*57194Smuller #include <sys/stat.h> 19*57194Smuller #include <sys/param.h> 20*57194Smuller #include <string.h> 21*57194Smuller #include <stdio.h> 22*57194Smuller #include <ctype.h> 23*57194Smuller #include <pwd.h> 24*57194Smuller #include <grp.h> 25*57194Smuller #include <unistd.h> 26*57194Smuller #include <stdlib.h> 27*57194Smuller #include "pax.h" 28*57194Smuller #include "cache.h" 29*57194Smuller #include "extern.h" 30*57194Smuller 31*57194Smuller /* 32*57194Smuller * routines that control user, group, uid and gid caches (for the archive 33*57194Smuller * member print routine). 34*57194Smuller * IMPORTANT: 35*57194Smuller * these routines cache BOTH hits and misses, a major performance improvement 36*57194Smuller */ 37*57194Smuller 38*57194Smuller static int pwopn = 0; /* is password file open */ 39*57194Smuller static int gropn = 0; /* is group file open */ 40*57194Smuller static UIDC **uidtb = NULL; /* uid to name cache */ 41*57194Smuller static GIDC **gidtb = NULL; /* gid to name cache */ 42*57194Smuller static UIDC **usrtb = NULL; /* user name to uid cache */ 43*57194Smuller static GIDC **grptb = NULL; /* group name to gid cache */ 44*57194Smuller 45*57194Smuller /* 46*57194Smuller * uidtb_start 47*57194Smuller * creates an an empty uidtb 48*57194Smuller * Return: 49*57194Smuller * 0 if ok, -1 otherwise 50*57194Smuller */ 51*57194Smuller 52*57194Smuller #if __STDC__ 53*57194Smuller int 54*57194Smuller uidtb_start(void) 55*57194Smuller #else 56*57194Smuller int 57*57194Smuller uidtb_start() 58*57194Smuller #endif 59*57194Smuller { 60*57194Smuller static int fail = 0; 61*57194Smuller 62*57194Smuller if (uidtb != NULL) 63*57194Smuller return(0); 64*57194Smuller if (fail) 65*57194Smuller return(-1); 66*57194Smuller if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 67*57194Smuller ++fail; 68*57194Smuller warn(1, "Unable to allocate memory for user id cache table"); 69*57194Smuller return(-1); 70*57194Smuller } 71*57194Smuller return(0); 72*57194Smuller } 73*57194Smuller 74*57194Smuller /* 75*57194Smuller * gidtb_start 76*57194Smuller * creates an an empty gidtb 77*57194Smuller * Return: 78*57194Smuller * 0 if ok, -1 otherwise 79*57194Smuller */ 80*57194Smuller 81*57194Smuller #if __STDC__ 82*57194Smuller int 83*57194Smuller gidtb_start(void) 84*57194Smuller #else 85*57194Smuller int 86*57194Smuller gidtb_start() 87*57194Smuller #endif 88*57194Smuller { 89*57194Smuller static int fail = 0; 90*57194Smuller 91*57194Smuller if (gidtb != NULL) 92*57194Smuller return(0); 93*57194Smuller if (fail) 94*57194Smuller return(-1); 95*57194Smuller if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 96*57194Smuller ++fail; 97*57194Smuller warn(1, "Unable to allocate memory for group id cache table"); 98*57194Smuller return(-1); 99*57194Smuller } 100*57194Smuller return(0); 101*57194Smuller } 102*57194Smuller 103*57194Smuller /* 104*57194Smuller * usrtb_start 105*57194Smuller * creates an an empty usrtb 106*57194Smuller * Return: 107*57194Smuller * 0 if ok, -1 otherwise 108*57194Smuller */ 109*57194Smuller 110*57194Smuller #if __STDC__ 111*57194Smuller int 112*57194Smuller usrtb_start(void) 113*57194Smuller #else 114*57194Smuller int 115*57194Smuller usrtb_start() 116*57194Smuller #endif 117*57194Smuller { 118*57194Smuller static int fail = 0; 119*57194Smuller 120*57194Smuller if (usrtb != NULL) 121*57194Smuller return(0); 122*57194Smuller if (fail) 123*57194Smuller return(-1); 124*57194Smuller if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 125*57194Smuller ++fail; 126*57194Smuller warn(1, "Unable to allocate memory for user name cache table"); 127*57194Smuller return(-1); 128*57194Smuller } 129*57194Smuller return(0); 130*57194Smuller } 131*57194Smuller 132*57194Smuller /* 133*57194Smuller * grptb_start 134*57194Smuller * creates an an empty grptb 135*57194Smuller * Return: 136*57194Smuller * 0 if ok, -1 otherwise 137*57194Smuller */ 138*57194Smuller 139*57194Smuller #if __STDC__ 140*57194Smuller int 141*57194Smuller grptb_start(void) 142*57194Smuller #else 143*57194Smuller int 144*57194Smuller grptb_start() 145*57194Smuller #endif 146*57194Smuller { 147*57194Smuller static int fail = 0; 148*57194Smuller 149*57194Smuller if (grptb != NULL) 150*57194Smuller return(0); 151*57194Smuller if (fail) 152*57194Smuller return(-1); 153*57194Smuller if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 154*57194Smuller ++fail; 155*57194Smuller warn(1,"Unable to allocate memory for group name cache table"); 156*57194Smuller return(-1); 157*57194Smuller } 158*57194Smuller return(0); 159*57194Smuller } 160*57194Smuller 161*57194Smuller /* 162*57194Smuller * name_uid() 163*57194Smuller * caches the name (if any) for the uid. If frc set, we always return the 164*57194Smuller * the stored name (if valid or invalid match). We use a simple hash table. 165*57194Smuller * Return 166*57194Smuller * Pointer to stored name (or a empty string) 167*57194Smuller */ 168*57194Smuller 169*57194Smuller #if __STDC__ 170*57194Smuller char * 171*57194Smuller name_uid(uid_t uid, int frc) 172*57194Smuller #else 173*57194Smuller char * 174*57194Smuller name_uid(uid, frc) 175*57194Smuller uid_t uid; 176*57194Smuller int frc; 177*57194Smuller #endif 178*57194Smuller { 179*57194Smuller register struct passwd *pw; 180*57194Smuller register UIDC *ptr; 181*57194Smuller 182*57194Smuller if ((uidtb == NULL) && (uidtb_start() < 0)) 183*57194Smuller return(""); 184*57194Smuller 185*57194Smuller /* 186*57194Smuller * see if we have this uid cached 187*57194Smuller */ 188*57194Smuller ptr = uidtb[uid % UID_SZ]; 189*57194Smuller if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { 190*57194Smuller /* 191*57194Smuller * have an entry for this uid 192*57194Smuller */ 193*57194Smuller if (frc || (ptr->valid == VALID)) 194*57194Smuller return(ptr->name); 195*57194Smuller return(""); 196*57194Smuller } 197*57194Smuller 198*57194Smuller /* 199*57194Smuller * No entry for this uid, we will add it 200*57194Smuller */ 201*57194Smuller if (!pwopn) { 202*57194Smuller setpassent(1); 203*57194Smuller ++pwopn; 204*57194Smuller } 205*57194Smuller if (ptr == NULL) 206*57194Smuller ptr = (UIDC *)malloc(sizeof(UIDC)); 207*57194Smuller 208*57194Smuller if ((pw = getpwuid(uid)) == NULL) { 209*57194Smuller /* 210*57194Smuller * no match for this uid in the local password file 211*57194Smuller * a string that is the uid in numberic format 212*57194Smuller */ 213*57194Smuller if (ptr == NULL) 214*57194Smuller return(""); 215*57194Smuller ptr->uid = uid; 216*57194Smuller ptr->valid = INVALID; 217*57194Smuller # ifdef NET2_STAT 218*57194Smuller (void)sprintf(ptr->name, "%u", uid); 219*57194Smuller # else 220*57194Smuller (void)sprintf(ptr->name, "%lu", uid); 221*57194Smuller # endif 222*57194Smuller if (frc == 0) 223*57194Smuller return(""); 224*57194Smuller } else { 225*57194Smuller /* 226*57194Smuller * there is an entry for this uid in the password file 227*57194Smuller */ 228*57194Smuller if (ptr == NULL) 229*57194Smuller return(pw->pw_name); 230*57194Smuller ptr->uid = uid; 231*57194Smuller (void)strncpy(ptr->name, pw->pw_name, UNMLEN); 232*57194Smuller ptr->name[UNMLEN-1] = '\0'; 233*57194Smuller ptr->valid = VALID; 234*57194Smuller } 235*57194Smuller return(ptr->name); 236*57194Smuller } 237*57194Smuller 238*57194Smuller /* 239*57194Smuller * name_gid() 240*57194Smuller * caches the name (if any) for the gid. If frc set, we always return the 241*57194Smuller * the stored name (if valid or invalid match). We use a simple hash table. 242*57194Smuller * Return 243*57194Smuller * Pointer to stored name (or a empty string) 244*57194Smuller */ 245*57194Smuller 246*57194Smuller #if __STDC__ 247*57194Smuller char * 248*57194Smuller name_gid(gid_t gid, int frc) 249*57194Smuller #else 250*57194Smuller char * 251*57194Smuller name_gid(gid, frc) 252*57194Smuller gid_t gid; 253*57194Smuller int frc; 254*57194Smuller #endif 255*57194Smuller { 256*57194Smuller register struct group *gr; 257*57194Smuller register GIDC *ptr; 258*57194Smuller 259*57194Smuller if ((gidtb == NULL) && (gidtb_start() < 0)) 260*57194Smuller return(""); 261*57194Smuller 262*57194Smuller /* 263*57194Smuller * see if we have this gid cached 264*57194Smuller */ 265*57194Smuller ptr = gidtb[gid % GID_SZ]; 266*57194Smuller if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 267*57194Smuller /* 268*57194Smuller * have an entry for this gid 269*57194Smuller */ 270*57194Smuller if (frc || (ptr->valid == VALID)) 271*57194Smuller return(ptr->name); 272*57194Smuller return(""); 273*57194Smuller } 274*57194Smuller 275*57194Smuller /* 276*57194Smuller * No entry for this gid, we will add it 277*57194Smuller */ 278*57194Smuller if (!gropn) { 279*57194Smuller setgroupent(1); 280*57194Smuller ++gropn; 281*57194Smuller } 282*57194Smuller if (ptr == NULL) 283*57194Smuller ptr = (GIDC *)malloc(sizeof(GIDC)); 284*57194Smuller 285*57194Smuller if ((gr = getgrgid(gid)) == NULL) { 286*57194Smuller /* 287*57194Smuller * no match for this gid in the local group file, put in 288*57194Smuller * a string that is the gid in numberic format 289*57194Smuller */ 290*57194Smuller if (ptr == NULL) 291*57194Smuller return(""); 292*57194Smuller ptr->gid = gid; 293*57194Smuller ptr->valid = INVALID; 294*57194Smuller # ifdef NET2_STAT 295*57194Smuller (void)sprintf(ptr->name, "%u", gid); 296*57194Smuller # else 297*57194Smuller (void)sprintf(ptr->name, "%lu", gid); 298*57194Smuller # endif 299*57194Smuller if (frc == 0) 300*57194Smuller return(""); 301*57194Smuller } else { 302*57194Smuller /* 303*57194Smuller * there is an entry for this group in the group file 304*57194Smuller */ 305*57194Smuller if (ptr == NULL) 306*57194Smuller return(gr->gr_name); 307*57194Smuller ptr->gid = gid; 308*57194Smuller (void)strncpy(ptr->name, gr->gr_name, GNMLEN); 309*57194Smuller ptr->name[GNMLEN-1] = '\0'; 310*57194Smuller ptr->valid = VALID; 311*57194Smuller } 312*57194Smuller return(ptr->name); 313*57194Smuller } 314*57194Smuller 315*57194Smuller /* 316*57194Smuller * uid_name() 317*57194Smuller * caches the uid for a given user name. We use a simple hash table. 318*57194Smuller * Return 319*57194Smuller * the uid (if any) for a user name, or a -1 if no match can be found 320*57194Smuller */ 321*57194Smuller 322*57194Smuller #if __STDC__ 323*57194Smuller int 324*57194Smuller uid_name(char *name, uid_t *uid) 325*57194Smuller #else 326*57194Smuller int 327*57194Smuller uid_name(name, uid) 328*57194Smuller char *name; 329*57194Smuller uid_t *uid; 330*57194Smuller #endif 331*57194Smuller { 332*57194Smuller register struct passwd *pw; 333*57194Smuller register UIDC *ptr; 334*57194Smuller register int namelen; 335*57194Smuller 336*57194Smuller /* 337*57194Smuller * return -1 for mangled names 338*57194Smuller */ 339*57194Smuller if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 340*57194Smuller return(-1); 341*57194Smuller if ((usrtb == NULL) && (usrtb_start() < 0)) 342*57194Smuller return(-1); 343*57194Smuller 344*57194Smuller /* 345*57194Smuller * look up in hash table, if found and valid return the uid, 346*57194Smuller * if found and invalid, return a -1 347*57194Smuller */ 348*57194Smuller ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 349*57194Smuller if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 350*57194Smuller if (ptr->valid == INVALID) 351*57194Smuller return(-1); 352*57194Smuller *uid = ptr->uid; 353*57194Smuller return(0); 354*57194Smuller } 355*57194Smuller 356*57194Smuller if (!pwopn) { 357*57194Smuller setpassent(1); 358*57194Smuller ++pwopn; 359*57194Smuller } 360*57194Smuller 361*57194Smuller if (ptr == NULL) 362*57194Smuller ptr = (UIDC *)malloc(sizeof(UIDC)); 363*57194Smuller 364*57194Smuller /* 365*57194Smuller * no match, look it up, if no match store it as an invalid entry, 366*57194Smuller * or store the matching uid 367*57194Smuller */ 368*57194Smuller if (ptr == NULL) { 369*57194Smuller if ((pw = getpwnam(name)) == NULL) 370*57194Smuller return(-1); 371*57194Smuller *uid = pw->pw_uid; 372*57194Smuller return(0); 373*57194Smuller } 374*57194Smuller (void)strncpy(ptr->name, name, UNMLEN); 375*57194Smuller ptr->name[UNMLEN-1] = '\0'; 376*57194Smuller if ((pw = getpwnam(name)) == NULL) { 377*57194Smuller ptr->valid = INVALID; 378*57194Smuller return(-1); 379*57194Smuller } 380*57194Smuller ptr->valid = VALID; 381*57194Smuller *uid = ptr->uid = pw->pw_uid; 382*57194Smuller return(0); 383*57194Smuller } 384*57194Smuller 385*57194Smuller /* 386*57194Smuller * gid_name() 387*57194Smuller * caches the gid for a given group name. We use a simple hash table. 388*57194Smuller * Return 389*57194Smuller * the gid (if any) for a group name, or a -1 if no match can be found 390*57194Smuller */ 391*57194Smuller 392*57194Smuller #if __STDC__ 393*57194Smuller int 394*57194Smuller gid_name(char *name, gid_t *gid) 395*57194Smuller #else 396*57194Smuller int 397*57194Smuller gid_name(name, gid) 398*57194Smuller char *name; 399*57194Smuller gid_t *gid; 400*57194Smuller #endif 401*57194Smuller { 402*57194Smuller register struct group *gr; 403*57194Smuller register GIDC *ptr; 404*57194Smuller register int namelen; 405*57194Smuller 406*57194Smuller /* 407*57194Smuller * return -1 for mangled names 408*57194Smuller */ 409*57194Smuller if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 410*57194Smuller return(-1); 411*57194Smuller if ((grptb == NULL) && (grptb_start() < 0)) 412*57194Smuller return(-1); 413*57194Smuller 414*57194Smuller /* 415*57194Smuller * look up in hash table, if found and valid return the uid, 416*57194Smuller * if found and invalid, return a -1 417*57194Smuller */ 418*57194Smuller ptr = grptb[st_hash(name, namelen, GID_SZ)]; 419*57194Smuller if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 420*57194Smuller if (ptr->valid == INVALID) 421*57194Smuller return(-1); 422*57194Smuller *gid = ptr->gid; 423*57194Smuller return(0); 424*57194Smuller } 425*57194Smuller 426*57194Smuller if (!gropn) { 427*57194Smuller setgroupent(1); 428*57194Smuller ++pwopn; 429*57194Smuller } 430*57194Smuller if (ptr == NULL) 431*57194Smuller ptr = (GIDC *)malloc(sizeof(GIDC)); 432*57194Smuller 433*57194Smuller /* 434*57194Smuller * no match, look it up, if no match store it as an invalid entry, 435*57194Smuller * or store the matching gid 436*57194Smuller */ 437*57194Smuller if (ptr == NULL) { 438*57194Smuller if ((gr = getgrnam(name)) == NULL) 439*57194Smuller return(-1); 440*57194Smuller *gid = gr->gr_gid; 441*57194Smuller return(0); 442*57194Smuller } 443*57194Smuller 444*57194Smuller (void)strncpy(ptr->name, name, GNMLEN); 445*57194Smuller ptr->name[GNMLEN-1] = '\0'; 446*57194Smuller if ((gr = getgrnam(name)) == NULL) { 447*57194Smuller ptr->valid = INVALID; 448*57194Smuller return(-1); 449*57194Smuller } 450*57194Smuller ptr->valid = VALID; 451*57194Smuller *gid = ptr->gid = gr->gr_gid; 452*57194Smuller return(0); 453*57194Smuller } 454