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