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 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * $Id: cache.c,v 1.7 1997/06/02 06:30:06 charnier Exp $ 38 */ 39 40 #ifndef lint 41 static char const sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; 42 #endif /* not lint */ 43 44 #include <sys/types.h> 45 #include <sys/time.h> 46 #include <sys/stat.h> 47 #include <sys/param.h> 48 #include <string.h> 49 #include <stdio.h> 50 #include <pwd.h> 51 #include <grp.h> 52 #include <unistd.h> 53 #include <stdlib.h> 54 #include "pax.h" 55 #include "cache.h" 56 #include "extern.h" 57 58 /* 59 * routines that control user, group, uid and gid caches (for the archive 60 * member print routine). 61 * IMPORTANT: 62 * these routines cache BOTH hits and misses, a major performance improvement 63 */ 64 65 static int pwopn = 0; /* is password file open */ 66 static int gropn = 0; /* is group file open */ 67 static UIDC **uidtb = NULL; /* uid to name cache */ 68 static GIDC **gidtb = NULL; /* gid to name cache */ 69 static UIDC **usrtb = NULL; /* user name to uid cache */ 70 static GIDC **grptb = NULL; /* group name to gid cache */ 71 72 /* 73 * uidtb_start 74 * creates an an empty uidtb 75 * Return: 76 * 0 if ok, -1 otherwise 77 */ 78 79 #if __STDC__ 80 int 81 uidtb_start(void) 82 #else 83 int 84 uidtb_start() 85 #endif 86 { 87 static int fail = 0; 88 89 if (uidtb != NULL) 90 return(0); 91 if (fail) 92 return(-1); 93 if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 94 ++fail; 95 pax_warn(1, "Unable to allocate memory for user id cache table"); 96 return(-1); 97 } 98 return(0); 99 } 100 101 /* 102 * gidtb_start 103 * creates an an empty gidtb 104 * Return: 105 * 0 if ok, -1 otherwise 106 */ 107 108 #if __STDC__ 109 int 110 gidtb_start(void) 111 #else 112 int 113 gidtb_start() 114 #endif 115 { 116 static int fail = 0; 117 118 if (gidtb != NULL) 119 return(0); 120 if (fail) 121 return(-1); 122 if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 123 ++fail; 124 pax_warn(1, "Unable to allocate memory for group id cache table"); 125 return(-1); 126 } 127 return(0); 128 } 129 130 /* 131 * usrtb_start 132 * creates an an empty usrtb 133 * Return: 134 * 0 if ok, -1 otherwise 135 */ 136 137 #if __STDC__ 138 int 139 usrtb_start(void) 140 #else 141 int 142 usrtb_start() 143 #endif 144 { 145 static int fail = 0; 146 147 if (usrtb != NULL) 148 return(0); 149 if (fail) 150 return(-1); 151 if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 152 ++fail; 153 pax_warn(1, "Unable to allocate memory for user name cache table"); 154 return(-1); 155 } 156 return(0); 157 } 158 159 /* 160 * grptb_start 161 * creates an an empty grptb 162 * Return: 163 * 0 if ok, -1 otherwise 164 */ 165 166 #if __STDC__ 167 int 168 grptb_start(void) 169 #else 170 int 171 grptb_start() 172 #endif 173 { 174 static int fail = 0; 175 176 if (grptb != NULL) 177 return(0); 178 if (fail) 179 return(-1); 180 if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 181 ++fail; 182 pax_warn(1,"Unable to allocate memory for group name cache table"); 183 return(-1); 184 } 185 return(0); 186 } 187 188 /* 189 * name_uid() 190 * caches the name (if any) for the uid. If frc set, we always return the 191 * the stored name (if valid or invalid match). We use a simple hash table. 192 * Return 193 * Pointer to stored name (or a empty string) 194 */ 195 196 #if __STDC__ 197 char * 198 name_uid(uid_t uid, int frc) 199 #else 200 char * 201 name_uid(uid, frc) 202 uid_t uid; 203 int frc; 204 #endif 205 { 206 register struct passwd *pw; 207 register UIDC *ptr; 208 209 if ((uidtb == NULL) && (uidtb_start() < 0)) 210 return(""); 211 212 /* 213 * see if we have this uid cached 214 */ 215 ptr = uidtb[uid % UID_SZ]; 216 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { 217 /* 218 * have an entry for this uid 219 */ 220 if (frc || (ptr->valid == VALID)) 221 return(ptr->name); 222 return(""); 223 } 224 225 /* 226 * No entry for this uid, we will add it 227 */ 228 if (!pwopn) { 229 setpassent(1); 230 ++pwopn; 231 } 232 if (ptr == NULL) 233 ptr = (UIDC *)malloc(sizeof(UIDC)); 234 235 if ((pw = getpwuid(uid)) == NULL) { 236 /* 237 * no match for this uid in the local password file 238 * a string that is the uid in numberic format 239 */ 240 if (ptr == NULL) 241 return(""); 242 ptr->uid = uid; 243 ptr->valid = INVALID; 244 # ifdef NET2_STAT 245 (void)sprintf(ptr->name, "%u", uid); 246 # else 247 (void)sprintf(ptr->name, "%lu", (u_long)uid); 248 # endif 249 if (frc == 0) 250 return(""); 251 } else { 252 /* 253 * there is an entry for this uid in the password file 254 */ 255 if (ptr == NULL) 256 return(pw->pw_name); 257 ptr->uid = uid; 258 (void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1); 259 ptr->name[UNMLEN-1] = '\0'; 260 ptr->valid = VALID; 261 } 262 return(ptr->name); 263 } 264 265 /* 266 * name_gid() 267 * caches the name (if any) for the gid. If frc set, we always return the 268 * the stored name (if valid or invalid match). We use a simple hash table. 269 * Return 270 * Pointer to stored name (or a empty string) 271 */ 272 273 #if __STDC__ 274 char * 275 name_gid(gid_t gid, int frc) 276 #else 277 char * 278 name_gid(gid, frc) 279 gid_t gid; 280 int frc; 281 #endif 282 { 283 register struct group *gr; 284 register GIDC *ptr; 285 286 if ((gidtb == NULL) && (gidtb_start() < 0)) 287 return(""); 288 289 /* 290 * see if we have this gid cached 291 */ 292 ptr = gidtb[gid % GID_SZ]; 293 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 294 /* 295 * have an entry for this gid 296 */ 297 if (frc || (ptr->valid == VALID)) 298 return(ptr->name); 299 return(""); 300 } 301 302 /* 303 * No entry for this gid, we will add it 304 */ 305 if (!gropn) { 306 setgroupent(1); 307 ++gropn; 308 } 309 if (ptr == NULL) 310 ptr = (GIDC *)malloc(sizeof(GIDC)); 311 312 if ((gr = getgrgid(gid)) == NULL) { 313 /* 314 * no match for this gid in the local group file, put in 315 * a string that is the gid in numberic format 316 */ 317 if (ptr == NULL) 318 return(""); 319 ptr->gid = gid; 320 ptr->valid = INVALID; 321 # ifdef NET2_STAT 322 (void)sprintf(ptr->name, "%u", gid); 323 # else 324 (void)sprintf(ptr->name, "%lu", (u_long)gid); 325 # endif 326 if (frc == 0) 327 return(""); 328 } else { 329 /* 330 * there is an entry for this group in the group file 331 */ 332 if (ptr == NULL) 333 return(gr->gr_name); 334 ptr->gid = gid; 335 (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1); 336 ptr->name[GNMLEN-1] = '\0'; 337 ptr->valid = VALID; 338 } 339 return(ptr->name); 340 } 341 342 /* 343 * uid_name() 344 * caches the uid for a given user name. We use a simple hash table. 345 * Return 346 * the uid (if any) for a user name, or a -1 if no match can be found 347 */ 348 349 #if __STDC__ 350 int 351 uid_name(char *name, uid_t *uid) 352 #else 353 int 354 uid_name(name, uid) 355 char *name; 356 uid_t *uid; 357 #endif 358 { 359 register struct passwd *pw; 360 register UIDC *ptr; 361 register int namelen; 362 363 /* 364 * return -1 for mangled names 365 */ 366 if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 367 return(-1); 368 if ((usrtb == NULL) && (usrtb_start() < 0)) 369 return(-1); 370 371 /* 372 * look up in hash table, if found and valid return the uid, 373 * if found and invalid, return a -1 374 */ 375 ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 376 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 377 if (ptr->valid == INVALID) 378 return(-1); 379 *uid = ptr->uid; 380 return(0); 381 } 382 383 if (!pwopn) { 384 setpassent(1); 385 ++pwopn; 386 } 387 388 if (ptr == NULL) 389 ptr = (UIDC *)malloc(sizeof(UIDC)); 390 391 /* 392 * no match, look it up, if no match store it as an invalid entry, 393 * or store the matching uid 394 */ 395 if (ptr == NULL) { 396 if ((pw = getpwnam(name)) == NULL) 397 return(-1); 398 *uid = pw->pw_uid; 399 return(0); 400 } 401 (void)strncpy(ptr->name, name, UNMLEN - 1); 402 ptr->name[UNMLEN-1] = '\0'; 403 if ((pw = getpwnam(name)) == NULL) { 404 ptr->valid = INVALID; 405 return(-1); 406 } 407 ptr->valid = VALID; 408 *uid = ptr->uid = pw->pw_uid; 409 return(0); 410 } 411 412 /* 413 * gid_name() 414 * caches the gid for a given group name. We use a simple hash table. 415 * Return 416 * the gid (if any) for a group name, or a -1 if no match can be found 417 */ 418 419 #if __STDC__ 420 int 421 gid_name(char *name, gid_t *gid) 422 #else 423 int 424 gid_name(name, gid) 425 char *name; 426 gid_t *gid; 427 #endif 428 { 429 register struct group *gr; 430 register GIDC *ptr; 431 register int namelen; 432 433 /* 434 * return -1 for mangled names 435 */ 436 if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 437 return(-1); 438 if ((grptb == NULL) && (grptb_start() < 0)) 439 return(-1); 440 441 /* 442 * look up in hash table, if found and valid return the uid, 443 * if found and invalid, return a -1 444 */ 445 ptr = grptb[st_hash(name, namelen, GID_SZ)]; 446 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 447 if (ptr->valid == INVALID) 448 return(-1); 449 *gid = ptr->gid; 450 return(0); 451 } 452 453 if (!gropn) { 454 setgroupent(1); 455 ++gropn; 456 } 457 if (ptr == NULL) 458 ptr = (GIDC *)malloc(sizeof(GIDC)); 459 460 /* 461 * no match, look it up, if no match store it as an invalid entry, 462 * or store the matching gid 463 */ 464 if (ptr == NULL) { 465 if ((gr = getgrnam(name)) == NULL) 466 return(-1); 467 *gid = gr->gr_gid; 468 return(0); 469 } 470 471 (void)strncpy(ptr->name, name, GNMLEN - 1); 472 ptr->name[GNMLEN-1] = '\0'; 473 if ((gr = getgrnam(name)) == NULL) { 474 ptr->valid = INVALID; 475 return(-1); 476 } 477 ptr->valid = VALID; 478 *gid = ptr->gid = gr->gr_gid; 479 return(0); 480 } 481