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 #if 0 40 static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; 41 #endif 42 static const char rcsid[] = 43 "$FreeBSD$"; 44 #endif /* not lint */ 45 46 #include <sys/types.h> 47 #include <sys/stat.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 int 80 uidtb_start(void) 81 { 82 static int fail = 0; 83 84 if (uidtb != NULL) 85 return(0); 86 if (fail) 87 return(-1); 88 if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 89 ++fail; 90 paxwarn(1, "Unable to allocate memory for user id cache table"); 91 return(-1); 92 } 93 return(0); 94 } 95 96 /* 97 * gidtb_start 98 * creates an an empty gidtb 99 * Return: 100 * 0 if ok, -1 otherwise 101 */ 102 103 int 104 gidtb_start(void) 105 { 106 static int fail = 0; 107 108 if (gidtb != NULL) 109 return(0); 110 if (fail) 111 return(-1); 112 if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 113 ++fail; 114 paxwarn(1, "Unable to allocate memory for group id cache table"); 115 return(-1); 116 } 117 return(0); 118 } 119 120 /* 121 * usrtb_start 122 * creates an an empty usrtb 123 * Return: 124 * 0 if ok, -1 otherwise 125 */ 126 127 int 128 usrtb_start(void) 129 { 130 static int fail = 0; 131 132 if (usrtb != NULL) 133 return(0); 134 if (fail) 135 return(-1); 136 if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 137 ++fail; 138 paxwarn(1, "Unable to allocate memory for user name cache table"); 139 return(-1); 140 } 141 return(0); 142 } 143 144 /* 145 * grptb_start 146 * creates an an empty grptb 147 * Return: 148 * 0 if ok, -1 otherwise 149 */ 150 151 int 152 grptb_start(void) 153 { 154 static int fail = 0; 155 156 if (grptb != NULL) 157 return(0); 158 if (fail) 159 return(-1); 160 if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 161 ++fail; 162 paxwarn(1,"Unable to allocate memory for group name cache table"); 163 return(-1); 164 } 165 return(0); 166 } 167 168 /* 169 * name_uid() 170 * caches the name (if any) for the uid. If frc set, we always return the 171 * the stored name (if valid or invalid match). We use a simple hash table. 172 * Return 173 * Pointer to stored name (or a empty string) 174 */ 175 176 char * 177 name_uid(uid_t uid, int frc) 178 { 179 struct passwd *pw; 180 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 numeric format 212 */ 213 if (ptr == NULL) 214 return(""); 215 ptr->uid = uid; 216 ptr->valid = INVALID; 217 # ifdef NET2_STAT 218 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid); 219 # else 220 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", 221 (unsigned long)uid); 222 # endif 223 if (frc == 0) 224 return(""); 225 } else { 226 /* 227 * there is an entry for this uid in the password file 228 */ 229 if (ptr == NULL) 230 return(pw->pw_name); 231 ptr->uid = uid; 232 (void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1); 233 ptr->name[UNMLEN-1] = '\0'; 234 ptr->valid = VALID; 235 } 236 return(ptr->name); 237 } 238 239 /* 240 * name_gid() 241 * caches the name (if any) for the gid. If frc set, we always return the 242 * the stored name (if valid or invalid match). We use a simple hash table. 243 * Return 244 * Pointer to stored name (or a empty string) 245 */ 246 247 char * 248 name_gid(gid_t gid, int frc) 249 { 250 struct group *gr; 251 GIDC *ptr; 252 253 if ((gidtb == NULL) && (gidtb_start() < 0)) 254 return(""); 255 256 /* 257 * see if we have this gid cached 258 */ 259 ptr = gidtb[gid % GID_SZ]; 260 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 261 /* 262 * have an entry for this gid 263 */ 264 if (frc || (ptr->valid == VALID)) 265 return(ptr->name); 266 return(""); 267 } 268 269 /* 270 * No entry for this gid, we will add it 271 */ 272 if (!gropn) { 273 setgroupent(1); 274 ++gropn; 275 } 276 if (ptr == NULL) 277 ptr = (GIDC *)malloc(sizeof(GIDC)); 278 279 if ((gr = getgrgid(gid)) == NULL) { 280 /* 281 * no match for this gid in the local group file, put in 282 * a string that is the gid in numeric format 283 */ 284 if (ptr == NULL) 285 return(""); 286 ptr->gid = gid; 287 ptr->valid = INVALID; 288 # ifdef NET2_STAT 289 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid); 290 # else 291 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", 292 (unsigned long)gid); 293 # endif 294 if (frc == 0) 295 return(""); 296 } else { 297 /* 298 * there is an entry for this group in the group file 299 */ 300 if (ptr == NULL) 301 return(gr->gr_name); 302 ptr->gid = gid; 303 (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1); 304 ptr->name[GNMLEN-1] = '\0'; 305 ptr->valid = VALID; 306 } 307 return(ptr->name); 308 } 309 310 /* 311 * uid_name() 312 * caches the uid for a given user name. We use a simple hash table. 313 * Return 314 * the uid (if any) for a user name, or a -1 if no match can be found 315 */ 316 317 int 318 uid_name(char *name, uid_t *uid) 319 { 320 struct passwd *pw; 321 UIDC *ptr; 322 int namelen; 323 324 /* 325 * return -1 for mangled names 326 */ 327 if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 328 return(-1); 329 if ((usrtb == NULL) && (usrtb_start() < 0)) 330 return(-1); 331 332 /* 333 * look up in hash table, if found and valid return the uid, 334 * if found and invalid, return a -1 335 */ 336 ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; 337 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 338 if (ptr->valid == INVALID) 339 return(-1); 340 *uid = ptr->uid; 341 return(0); 342 } 343 344 if (!pwopn) { 345 setpassent(1); 346 ++pwopn; 347 } 348 349 if (ptr == NULL) 350 ptr = usrtb[st_hash(name, namelen, UNM_SZ)] = 351 (UIDC *)malloc(sizeof(UIDC)); 352 353 /* 354 * no match, look it up, if no match store it as an invalid entry, 355 * or store the matching uid 356 */ 357 if (ptr == NULL) { 358 if ((pw = getpwnam(name)) == NULL) 359 return(-1); 360 *uid = pw->pw_uid; 361 return(0); 362 } 363 (void)strncpy(ptr->name, name, UNMLEN - 1); 364 ptr->name[UNMLEN-1] = '\0'; 365 if ((pw = getpwnam(name)) == NULL) { 366 ptr->valid = INVALID; 367 return(-1); 368 } 369 ptr->valid = VALID; 370 *uid = ptr->uid = pw->pw_uid; 371 return(0); 372 } 373 374 /* 375 * gid_name() 376 * caches the gid for a given group name. We use a simple hash table. 377 * Return 378 * the gid (if any) for a group name, or a -1 if no match can be found 379 */ 380 381 int 382 gid_name(char *name, gid_t *gid) 383 { 384 struct group *gr; 385 GIDC *ptr; 386 int namelen; 387 388 /* 389 * return -1 for mangled names 390 */ 391 if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) 392 return(-1); 393 if ((grptb == NULL) && (grptb_start() < 0)) 394 return(-1); 395 396 /* 397 * look up in hash table, if found and valid return the uid, 398 * if found and invalid, return a -1 399 */ 400 ptr = grptb[st_hash(name, namelen, GID_SZ)]; 401 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 402 if (ptr->valid == INVALID) 403 return(-1); 404 *gid = ptr->gid; 405 return(0); 406 } 407 408 if (!gropn) { 409 setgroupent(1); 410 ++gropn; 411 } 412 if (ptr == NULL) 413 ptr = grptb[st_hash(name, namelen, GID_SZ)] = 414 (GIDC *)malloc(sizeof(GIDC)); 415 416 /* 417 * no match, look it up, if no match store it as an invalid entry, 418 * or store the matching gid 419 */ 420 if (ptr == NULL) { 421 if ((gr = getgrnam(name)) == NULL) 422 return(-1); 423 *gid = gr->gr_gid; 424 return(0); 425 } 426 427 (void)strncpy(ptr->name, name, GNMLEN - 1); 428 ptr->name[GNMLEN-1] = '\0'; 429 if ((gr = getgrnam(name)) == NULL) { 430 ptr->valid = INVALID; 431 return(-1); 432 } 433 ptr->valid = VALID; 434 *gid = ptr->gid = gr->gr_gid; 435 return(0); 436 } 437