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