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