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