157194Smuller /*- 257194Smuller * Copyright (c) 1992 Keith Muller. 357194Smuller * Copyright (c) 1992 The Regents of the University of California. 457194Smuller * All rights reserved. 557194Smuller * 657194Smuller * This code is derived from software contributed to Berkeley by 757194Smuller * Keith Muller of the University of California, San Diego. 857194Smuller * 957194Smuller * %sccs.include.redist.c% 1057194Smuller */ 1157194Smuller 1257194Smuller #ifndef lint 13*57573Smuller static char sccsid[] = "@(#)cache.c 1.2 (Berkeley) 01/15/93"; 1457194Smuller #endif /* not lint */ 1557194Smuller 1657194Smuller #include <sys/types.h> 1757194Smuller #include <sys/time.h> 1857194Smuller #include <sys/stat.h> 1957194Smuller #include <sys/param.h> 2057194Smuller #include <string.h> 2157194Smuller #include <stdio.h> 2257194Smuller #include <ctype.h> 2357194Smuller #include <pwd.h> 2457194Smuller #include <grp.h> 2557194Smuller #include <unistd.h> 2657194Smuller #include <stdlib.h> 2757194Smuller #include "pax.h" 2857194Smuller #include "cache.h" 2957194Smuller #include "extern.h" 3057194Smuller 3157194Smuller /* 3257194Smuller * routines that control user, group, uid and gid caches (for the archive 3357194Smuller * member print routine). 3457194Smuller * IMPORTANT: 3557194Smuller * these routines cache BOTH hits and misses, a major performance improvement 3657194Smuller */ 3757194Smuller 3857194Smuller static int pwopn = 0; /* is password file open */ 3957194Smuller static int gropn = 0; /* is group file open */ 4057194Smuller static UIDC **uidtb = NULL; /* uid to name cache */ 4157194Smuller static GIDC **gidtb = NULL; /* gid to name cache */ 4257194Smuller static UIDC **usrtb = NULL; /* user name to uid cache */ 4357194Smuller static GIDC **grptb = NULL; /* group name to gid cache */ 4457194Smuller 4557194Smuller /* 4657194Smuller * uidtb_start 4757194Smuller * creates an an empty uidtb 4857194Smuller * Return: 4957194Smuller * 0 if ok, -1 otherwise 5057194Smuller */ 5157194Smuller 5257194Smuller #if __STDC__ 5357194Smuller int 5457194Smuller uidtb_start(void) 5557194Smuller #else 5657194Smuller int 5757194Smuller uidtb_start() 5857194Smuller #endif 5957194Smuller { 6057194Smuller static int fail = 0; 6157194Smuller 6257194Smuller if (uidtb != NULL) 6357194Smuller return(0); 6457194Smuller if (fail) 6557194Smuller return(-1); 6657194Smuller if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 6757194Smuller ++fail; 6857194Smuller warn(1, "Unable to allocate memory for user id cache table"); 6957194Smuller return(-1); 7057194Smuller } 7157194Smuller return(0); 7257194Smuller } 7357194Smuller 7457194Smuller /* 7557194Smuller * gidtb_start 7657194Smuller * creates an an empty gidtb 7757194Smuller * Return: 7857194Smuller * 0 if ok, -1 otherwise 7957194Smuller */ 8057194Smuller 8157194Smuller #if __STDC__ 8257194Smuller int 8357194Smuller gidtb_start(void) 8457194Smuller #else 8557194Smuller int 8657194Smuller gidtb_start() 8757194Smuller #endif 8857194Smuller { 8957194Smuller static int fail = 0; 9057194Smuller 9157194Smuller if (gidtb != NULL) 9257194Smuller return(0); 9357194Smuller if (fail) 9457194Smuller return(-1); 9557194Smuller if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 9657194Smuller ++fail; 9757194Smuller warn(1, "Unable to allocate memory for group id cache table"); 9857194Smuller return(-1); 9957194Smuller } 10057194Smuller return(0); 10157194Smuller } 10257194Smuller 10357194Smuller /* 10457194Smuller * usrtb_start 10557194Smuller * creates an an empty usrtb 10657194Smuller * Return: 10757194Smuller * 0 if ok, -1 otherwise 10857194Smuller */ 10957194Smuller 11057194Smuller #if __STDC__ 11157194Smuller int 11257194Smuller usrtb_start(void) 11357194Smuller #else 11457194Smuller int 11557194Smuller usrtb_start() 11657194Smuller #endif 11757194Smuller { 11857194Smuller static int fail = 0; 11957194Smuller 12057194Smuller if (usrtb != NULL) 12157194Smuller return(0); 12257194Smuller if (fail) 12357194Smuller return(-1); 12457194Smuller if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 12557194Smuller ++fail; 12657194Smuller warn(1, "Unable to allocate memory for user name cache table"); 12757194Smuller return(-1); 12857194Smuller } 12957194Smuller return(0); 13057194Smuller } 13157194Smuller 13257194Smuller /* 13357194Smuller * grptb_start 13457194Smuller * creates an an empty grptb 13557194Smuller * Return: 13657194Smuller * 0 if ok, -1 otherwise 13757194Smuller */ 13857194Smuller 13957194Smuller #if __STDC__ 14057194Smuller int 14157194Smuller grptb_start(void) 14257194Smuller #else 14357194Smuller int 14457194Smuller grptb_start() 14557194Smuller #endif 14657194Smuller { 14757194Smuller static int fail = 0; 14857194Smuller 14957194Smuller if (grptb != NULL) 15057194Smuller return(0); 15157194Smuller if (fail) 15257194Smuller return(-1); 15357194Smuller if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 15457194Smuller ++fail; 15557194Smuller warn(1,"Unable to allocate memory for group name cache table"); 15657194Smuller return(-1); 15757194Smuller } 15857194Smuller return(0); 15957194Smuller } 16057194Smuller 16157194Smuller /* 16257194Smuller * name_uid() 16357194Smuller * caches the name (if any) for the uid. If frc set, we always return the 16457194Smuller * the stored name (if valid or invalid match). We use a simple hash table. 16557194Smuller * Return 16657194Smuller * Pointer to stored name (or a empty string) 16757194Smuller */ 16857194Smuller 16957194Smuller #if __STDC__ 17057194Smuller char * 17157194Smuller name_uid(uid_t uid, int frc) 17257194Smuller #else 17357194Smuller char * 17457194Smuller name_uid(uid, frc) 17557194Smuller uid_t uid; 17657194Smuller int frc; 17757194Smuller #endif 17857194Smuller { 17957194Smuller register struct passwd *pw; 18057194Smuller register UIDC *ptr; 18157194Smuller 18257194Smuller if ((uidtb == NULL) && (uidtb_start() < 0)) 18357194Smuller return(""); 18457194Smuller 18557194Smuller /* 18657194Smuller * see if we have this uid cached 18757194Smuller */ 18857194Smuller ptr = uidtb[uid % UID_SZ]; 18957194Smuller if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { 19057194Smuller /* 19157194Smuller * have an entry for this uid 19257194Smuller */ 19357194Smuller if (frc || (ptr->valid == VALID)) 19457194Smuller return(ptr->name); 19557194Smuller return(""); 19657194Smuller } 19757194Smuller 19857194Smuller /* 19957194Smuller * No entry for this uid, we will add it 20057194Smuller */ 20157194Smuller if (!pwopn) { 20257194Smuller setpassent(1); 20357194Smuller ++pwopn; 20457194Smuller } 20557194Smuller if (ptr == NULL) 20657194Smuller ptr = (UIDC *)malloc(sizeof(UIDC)); 20757194Smuller 20857194Smuller if ((pw = getpwuid(uid)) == NULL) { 20957194Smuller /* 21057194Smuller * no match for this uid in the local password file 21157194Smuller * a string that is the uid in numberic format 21257194Smuller */ 21357194Smuller if (ptr == NULL) 21457194Smuller return(""); 21557194Smuller ptr->uid = uid; 21657194Smuller ptr->valid = INVALID; 21757194Smuller # ifdef NET2_STAT 21857194Smuller (void)sprintf(ptr->name, "%u", uid); 21957194Smuller # else 22057194Smuller (void)sprintf(ptr->name, "%lu", uid); 22157194Smuller # endif 22257194Smuller if (frc == 0) 22357194Smuller return(""); 22457194Smuller } else { 22557194Smuller /* 22657194Smuller * there is an entry for this uid in the password file 22757194Smuller */ 22857194Smuller if (ptr == NULL) 22957194Smuller return(pw->pw_name); 23057194Smuller ptr->uid = uid; 23157194Smuller (void)strncpy(ptr->name, pw->pw_name, UNMLEN); 23257194Smuller ptr->name[UNMLEN-1] = '\0'; 23357194Smuller ptr->valid = VALID; 23457194Smuller } 23557194Smuller return(ptr->name); 23657194Smuller } 23757194Smuller 23857194Smuller /* 23957194Smuller * name_gid() 24057194Smuller * caches the name (if any) for the gid. If frc set, we always return the 24157194Smuller * the stored name (if valid or invalid match). We use a simple hash table. 24257194Smuller * Return 24357194Smuller * Pointer to stored name (or a empty string) 24457194Smuller */ 24557194Smuller 24657194Smuller #if __STDC__ 24757194Smuller char * 24857194Smuller name_gid(gid_t gid, int frc) 24957194Smuller #else 25057194Smuller char * 25157194Smuller name_gid(gid, frc) 25257194Smuller gid_t gid; 25357194Smuller int frc; 25457194Smuller #endif 25557194Smuller { 25657194Smuller register struct group *gr; 25757194Smuller register GIDC *ptr; 25857194Smuller 25957194Smuller if ((gidtb == NULL) && (gidtb_start() < 0)) 26057194Smuller return(""); 26157194Smuller 26257194Smuller /* 26357194Smuller * see if we have this gid cached 26457194Smuller */ 26557194Smuller ptr = gidtb[gid % GID_SZ]; 26657194Smuller if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 26757194Smuller /* 26857194Smuller * have an entry for this gid 26957194Smuller */ 27057194Smuller if (frc || (ptr->valid == VALID)) 27157194Smuller return(ptr->name); 27257194Smuller return(""); 27357194Smuller } 27457194Smuller 27557194Smuller /* 27657194Smuller * No entry for this gid, we will add it 27757194Smuller */ 27857194Smuller if (!gropn) { 27957194Smuller setgroupent(1); 28057194Smuller ++gropn; 28157194Smuller } 28257194Smuller if (ptr == NULL) 28357194Smuller ptr = (GIDC *)malloc(sizeof(GIDC)); 28457194Smuller 28557194Smuller if ((gr = getgrgid(gid)) == NULL) { 28657194Smuller /* 28757194Smuller * no match for this gid in the local group file, put in 28857194Smuller * a string that is the gid in numberic format 28957194Smuller */ 29057194Smuller if (ptr == NULL) 29157194Smuller return(""); 29257194Smuller ptr->gid = gid; 29357194Smuller ptr->valid = INVALID; 29457194Smuller # ifdef NET2_STAT 29557194Smuller (void)sprintf(ptr->name, "%u", gid); 29657194Smuller # else 29757194Smuller (void)sprintf(ptr->name, "%lu", gid); 29857194Smuller # endif 29957194Smuller if (frc == 0) 30057194Smuller return(""); 30157194Smuller } else { 30257194Smuller /* 30357194Smuller * there is an entry for this group in the group file 30457194Smuller */ 30557194Smuller if (ptr == NULL) 30657194Smuller return(gr->gr_name); 30757194Smuller ptr->gid = gid; 30857194Smuller (void)strncpy(ptr->name, gr->gr_name, GNMLEN); 30957194Smuller ptr->name[GNMLEN-1] = '\0'; 31057194Smuller ptr->valid = VALID; 31157194Smuller } 31257194Smuller return(ptr->name); 31357194Smuller } 31457194Smuller 31557194Smuller /* 31657194Smuller * uid_name() 31757194Smuller * caches the uid for a given user name. We use a simple hash table. 31857194Smuller * Return 31957194Smuller * the uid (if any) for a user name, or a -1 if no match can be found 32057194Smuller */ 32157194Smuller 32257194Smuller #if __STDC__ 32357194Smuller int 32457194Smuller uid_name(char *name, uid_t *uid) 32557194Smuller #else 32657194Smuller int 32757194Smuller uid_name(name, uid) 32857194Smuller char *name; 32957194Smuller uid_t *uid; 33057194Smuller #endif 33157194Smuller { 33257194Smuller register struct passwd *pw; 33357194Smuller register UIDC *ptr; 33457194Smuller register int namelen; 33557194Smuller 33657194Smuller /* 33757194Smuller * return -1 for mangled names 33857194Smuller */ 33957194Smuller if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 34057194Smuller return(-1); 34157194Smuller if ((usrtb == NULL) && (usrtb_start() < 0)) 34257194Smuller return(-1); 34357194Smuller 34457194Smuller /* 34557194Smuller * look up in hash table, if found and valid return the uid, 34657194Smuller * if found and invalid, return a -1 34757194Smuller */ 34857194Smuller ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 34957194Smuller if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 35057194Smuller if (ptr->valid == INVALID) 35157194Smuller return(-1); 35257194Smuller *uid = ptr->uid; 35357194Smuller return(0); 35457194Smuller } 35557194Smuller 35657194Smuller if (!pwopn) { 35757194Smuller setpassent(1); 35857194Smuller ++pwopn; 35957194Smuller } 36057194Smuller 36157194Smuller if (ptr == NULL) 36257194Smuller ptr = (UIDC *)malloc(sizeof(UIDC)); 36357194Smuller 36457194Smuller /* 36557194Smuller * no match, look it up, if no match store it as an invalid entry, 36657194Smuller * or store the matching uid 36757194Smuller */ 36857194Smuller if (ptr == NULL) { 36957194Smuller if ((pw = getpwnam(name)) == NULL) 37057194Smuller return(-1); 37157194Smuller *uid = pw->pw_uid; 37257194Smuller return(0); 37357194Smuller } 37457194Smuller (void)strncpy(ptr->name, name, UNMLEN); 37557194Smuller ptr->name[UNMLEN-1] = '\0'; 37657194Smuller if ((pw = getpwnam(name)) == NULL) { 37757194Smuller ptr->valid = INVALID; 37857194Smuller return(-1); 37957194Smuller } 38057194Smuller ptr->valid = VALID; 38157194Smuller *uid = ptr->uid = pw->pw_uid; 38257194Smuller return(0); 38357194Smuller } 38457194Smuller 38557194Smuller /* 38657194Smuller * gid_name() 38757194Smuller * caches the gid for a given group name. We use a simple hash table. 38857194Smuller * Return 38957194Smuller * the gid (if any) for a group name, or a -1 if no match can be found 39057194Smuller */ 39157194Smuller 39257194Smuller #if __STDC__ 39357194Smuller int 39457194Smuller gid_name(char *name, gid_t *gid) 39557194Smuller #else 39657194Smuller int 39757194Smuller gid_name(name, gid) 39857194Smuller char *name; 39957194Smuller gid_t *gid; 40057194Smuller #endif 40157194Smuller { 40257194Smuller register struct group *gr; 40357194Smuller register GIDC *ptr; 40457194Smuller register int namelen; 40557194Smuller 40657194Smuller /* 40757194Smuller * return -1 for mangled names 40857194Smuller */ 40957194Smuller if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 41057194Smuller return(-1); 41157194Smuller if ((grptb == NULL) && (grptb_start() < 0)) 41257194Smuller return(-1); 41357194Smuller 41457194Smuller /* 41557194Smuller * look up in hash table, if found and valid return the uid, 41657194Smuller * if found and invalid, return a -1 41757194Smuller */ 41857194Smuller ptr = grptb[st_hash(name, namelen, GID_SZ)]; 41957194Smuller if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 42057194Smuller if (ptr->valid == INVALID) 42157194Smuller return(-1); 42257194Smuller *gid = ptr->gid; 42357194Smuller return(0); 42457194Smuller } 42557194Smuller 42657194Smuller if (!gropn) { 42757194Smuller setgroupent(1); 428*57573Smuller ++gropn; 42957194Smuller } 43057194Smuller if (ptr == NULL) 43157194Smuller ptr = (GIDC *)malloc(sizeof(GIDC)); 43257194Smuller 43357194Smuller /* 43457194Smuller * no match, look it up, if no match store it as an invalid entry, 43557194Smuller * or store the matching gid 43657194Smuller */ 43757194Smuller if (ptr == NULL) { 43857194Smuller if ((gr = getgrnam(name)) == NULL) 43957194Smuller return(-1); 44057194Smuller *gid = gr->gr_gid; 44157194Smuller return(0); 44257194Smuller } 44357194Smuller 44457194Smuller (void)strncpy(ptr->name, name, GNMLEN); 44557194Smuller ptr->name[GNMLEN-1] = '\0'; 44657194Smuller if ((gr = getgrnam(name)) == NULL) { 44757194Smuller ptr->valid = INVALID; 44857194Smuller return(-1); 44957194Smuller } 45057194Smuller ptr->valid = VALID; 45157194Smuller *gid = ptr->gid = gr->gr_gid; 45257194Smuller return(0); 45357194Smuller } 454