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