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