1241233Sbrooks/* $NetBSD: pwcache.c,v 1.31 2010/03/23 20:28:59 drochner Exp $ */ 2241233Sbrooks 3241233Sbrooks/*- 4241233Sbrooks * Copyright (c) 1992 Keith Muller. 5241233Sbrooks * Copyright (c) 1992, 1993 6241233Sbrooks * The Regents of the University of California. All rights reserved. 7241233Sbrooks * 8241233Sbrooks * This code is derived from software contributed to Berkeley by 9241233Sbrooks * Keith Muller of the University of California, San Diego. 10241233Sbrooks * 11241233Sbrooks * Redistribution and use in source and binary forms, with or without 12241233Sbrooks * modification, are permitted provided that the following conditions 13241233Sbrooks * are met: 14241233Sbrooks * 1. Redistributions of source code must retain the above copyright 15241233Sbrooks * notice, this list of conditions and the following disclaimer. 16241233Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 17241233Sbrooks * notice, this list of conditions and the following disclaimer in the 18241233Sbrooks * documentation and/or other materials provided with the distribution. 19241233Sbrooks * 3. Neither the name of the University nor the names of its contributors 20241233Sbrooks * may be used to endorse or promote products derived from this software 21241233Sbrooks * without specific prior written permission. 22241233Sbrooks * 23241233Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24241233Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25241233Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26241233Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27241233Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28241233Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29241233Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30241233Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31241233Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32241233Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33241233Sbrooks * SUCH DAMAGE. 34241233Sbrooks */ 35241233Sbrooks 36241233Sbrooks/*- 37241233Sbrooks * Copyright (c) 2002 The NetBSD Foundation, Inc. 38241233Sbrooks * All rights reserved. 39241233Sbrooks * 40241233Sbrooks * Redistribution and use in source and binary forms, with or without 41241233Sbrooks * modification, are permitted provided that the following conditions 42241233Sbrooks * are met: 43241233Sbrooks * 1. Redistributions of source code must retain the above copyright 44241233Sbrooks * notice, this list of conditions and the following disclaimer. 45241233Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 46241233Sbrooks * notice, this list of conditions and the following disclaimer in the 47241233Sbrooks * documentation and/or other materials provided with the distribution. 48241233Sbrooks * 49241233Sbrooks * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 50241233Sbrooks * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51241233Sbrooks * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52241233Sbrooks * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 53241233Sbrooks * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54241233Sbrooks * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55241233Sbrooks * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56241233Sbrooks * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57241233Sbrooks * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58241233Sbrooks * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59241233Sbrooks * POSSIBILITY OF SUCH DAMAGE. 60241233Sbrooks */ 61241233Sbrooks 62241233Sbrooks#if HAVE_NBTOOL_CONFIG_H 63241233Sbrooks#include "nbtool_config.h" 64241233Sbrooks/* 65241233Sbrooks * XXX Undefine the renames of these functions so that we don't 66241233Sbrooks * XXX rename the versions found in the host's <pwd.h> by mistake! 67241233Sbrooks */ 68241233Sbrooks#undef group_from_gid 69241233Sbrooks#undef user_from_uid 70241233Sbrooks#endif 71241233Sbrooks 72241233Sbrooks#include <sys/cdefs.h> 73241233Sbrooks#if defined(LIBC_SCCS) && !defined(lint) 74241233Sbrooks#if 0 75241233Sbrooksstatic char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; 76241233Sbrooks#else 77241233Sbrooks__RCSID("$NetBSD: pwcache.c,v 1.31 2010/03/23 20:28:59 drochner Exp $"); 78241233Sbrooks#endif 79241233Sbrooks#endif /* LIBC_SCCS and not lint */ 80241731Sbrooks__FBSDID("$FreeBSD$"); 81241233Sbrooks 82241233Sbrooks#include "namespace.h" 83241233Sbrooks 84241233Sbrooks#include <sys/types.h> 85241233Sbrooks#include <sys/param.h> 86241233Sbrooks 87241233Sbrooks#include <assert.h> 88241233Sbrooks#include <grp.h> 89241233Sbrooks#include <pwd.h> 90241233Sbrooks#include <stdio.h> 91241233Sbrooks#include <stdlib.h> 92241233Sbrooks#include <string.h> 93241233Sbrooks#include <unistd.h> 94241233Sbrooks 95241731Sbrooks#define _DIAGASSERT(x) assert((x)) 96241731Sbrooks 97241233Sbrooks#if HAVE_NBTOOL_CONFIG_H 98241233Sbrooks/* XXX Now, re-apply the renaming that we undid above. */ 99241233Sbrooks#define group_from_gid __nbcompat_group_from_gid 100241233Sbrooks#define user_from_uid __nbcompat_user_from_uid 101241233Sbrooks#endif 102241233Sbrooks 103241233Sbrooks#ifdef __weak_alias 104241233Sbrooks__weak_alias(user_from_uid,_user_from_uid) 105241233Sbrooks__weak_alias(group_from_gid,_group_from_gid) 106241233Sbrooks__weak_alias(pwcache_groupdb,_pwcache_groupdb) 107241233Sbrooks#endif 108241233Sbrooks 109241233Sbrooks#if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H 110241233Sbrooks#include "pwcache.h" 111241233Sbrooks 112241233Sbrooks/* 113241233Sbrooks * routines that control user, group, uid and gid caches (for the archive 114241233Sbrooks * member print routine). 115241233Sbrooks * IMPORTANT: 116241233Sbrooks * these routines cache BOTH hits and misses, a major performance improvement 117241233Sbrooks */ 118241233Sbrooks 119241233Sbrooks/* 120241233Sbrooks * function pointers to various name lookup routines. 121241233Sbrooks * these may be changed as necessary. 122241233Sbrooks */ 123241233Sbrooksstatic int (*_pwcache_setgroupent)(int) = setgroupent; 124241233Sbrooksstatic void (*_pwcache_endgrent)(void) = endgrent; 125241233Sbrooksstatic struct group * (*_pwcache_getgrnam)(const char *) = getgrnam; 126241233Sbrooksstatic struct group * (*_pwcache_getgrgid)(gid_t) = getgrgid; 127241233Sbrooksstatic int (*_pwcache_setpassent)(int) = setpassent; 128241233Sbrooksstatic void (*_pwcache_endpwent)(void) = endpwent; 129241233Sbrooksstatic struct passwd * (*_pwcache_getpwnam)(const char *) = getpwnam; 130241233Sbrooksstatic struct passwd * (*_pwcache_getpwuid)(uid_t) = getpwuid; 131241233Sbrooks 132241233Sbrooks/* 133241233Sbrooks * internal state 134241233Sbrooks */ 135241233Sbrooksstatic int pwopn; /* is password file open */ 136241233Sbrooksstatic int gropn; /* is group file open */ 137241233Sbrooksstatic UIDC **uidtb; /* uid to name cache */ 138241233Sbrooksstatic GIDC **gidtb; /* gid to name cache */ 139241233Sbrooksstatic UIDC **usrtb; /* user name to uid cache */ 140241233Sbrooksstatic GIDC **grptb; /* group name to gid cache */ 141241233Sbrooks 142241233Sbrooksstatic int uidtb_fail; /* uidtb_start() failed ? */ 143241233Sbrooksstatic int gidtb_fail; /* gidtb_start() failed ? */ 144241233Sbrooksstatic int usrtb_fail; /* usrtb_start() failed ? */ 145241233Sbrooksstatic int grptb_fail; /* grptb_start() failed ? */ 146241233Sbrooks 147241233Sbrooks 148241233Sbrooksstatic u_int st_hash(const char *, size_t, int); 149241233Sbrooksstatic int uidtb_start(void); 150241233Sbrooksstatic int gidtb_start(void); 151241233Sbrooksstatic int usrtb_start(void); 152241233Sbrooksstatic int grptb_start(void); 153241233Sbrooks 154241233Sbrooks 155241233Sbrooksstatic u_int 156241233Sbrooksst_hash(const char *name, size_t len, int tabsz) 157241233Sbrooks{ 158241233Sbrooks u_int key = 0; 159241233Sbrooks 160241233Sbrooks _DIAGASSERT(name != NULL); 161241233Sbrooks 162241233Sbrooks while (len--) { 163241233Sbrooks key += *name++; 164241233Sbrooks key = (key << 8) | (key >> 24); 165241233Sbrooks } 166241233Sbrooks 167241233Sbrooks return (key % tabsz); 168241233Sbrooks} 169241233Sbrooks 170241233Sbrooks/* 171241233Sbrooks * uidtb_start 172241233Sbrooks * creates an an empty uidtb 173241233Sbrooks * Return: 174241233Sbrooks * 0 if ok, -1 otherwise 175241233Sbrooks */ 176241233Sbrooksstatic int 177241233Sbrooksuidtb_start(void) 178241233Sbrooks{ 179241233Sbrooks 180241233Sbrooks if (uidtb != NULL) 181241233Sbrooks return (0); 182241233Sbrooks if (uidtb_fail) 183241233Sbrooks return (-1); 184241233Sbrooks if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { 185241233Sbrooks ++uidtb_fail; 186241233Sbrooks return (-1); 187241233Sbrooks } 188241233Sbrooks return (0); 189241233Sbrooks} 190241233Sbrooks 191241233Sbrooks/* 192241233Sbrooks * gidtb_start 193241233Sbrooks * creates an an empty gidtb 194241233Sbrooks * Return: 195241233Sbrooks * 0 if ok, -1 otherwise 196241233Sbrooks */ 197241233Sbrooksstatic int 198241233Sbrooksgidtb_start(void) 199241233Sbrooks{ 200241233Sbrooks 201241233Sbrooks if (gidtb != NULL) 202241233Sbrooks return (0); 203241233Sbrooks if (gidtb_fail) 204241233Sbrooks return (-1); 205241233Sbrooks if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { 206241233Sbrooks ++gidtb_fail; 207241233Sbrooks return (-1); 208241233Sbrooks } 209241233Sbrooks return (0); 210241233Sbrooks} 211241233Sbrooks 212241233Sbrooks/* 213241233Sbrooks * usrtb_start 214241233Sbrooks * creates an an empty usrtb 215241233Sbrooks * Return: 216241233Sbrooks * 0 if ok, -1 otherwise 217241233Sbrooks */ 218241233Sbrooksstatic int 219241233Sbrooksusrtb_start(void) 220241233Sbrooks{ 221241233Sbrooks 222241233Sbrooks if (usrtb != NULL) 223241233Sbrooks return (0); 224241233Sbrooks if (usrtb_fail) 225241233Sbrooks return (-1); 226241233Sbrooks if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { 227241233Sbrooks ++usrtb_fail; 228241233Sbrooks return (-1); 229241233Sbrooks } 230241233Sbrooks return (0); 231241233Sbrooks} 232241233Sbrooks 233241233Sbrooks/* 234241233Sbrooks * grptb_start 235241233Sbrooks * creates an an empty grptb 236241233Sbrooks * Return: 237241233Sbrooks * 0 if ok, -1 otherwise 238241233Sbrooks */ 239241233Sbrooksstatic int 240241233Sbrooksgrptb_start(void) 241241233Sbrooks{ 242241233Sbrooks 243241233Sbrooks if (grptb != NULL) 244241233Sbrooks return (0); 245241233Sbrooks if (grptb_fail) 246241233Sbrooks return (-1); 247241233Sbrooks if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { 248241233Sbrooks ++grptb_fail; 249241233Sbrooks return (-1); 250241233Sbrooks } 251241233Sbrooks return (0); 252241233Sbrooks} 253241233Sbrooks 254241233Sbrooks/* 255241233Sbrooks * user_from_uid() 256241233Sbrooks * caches the name (if any) for the uid. If noname clear, we always 257241233Sbrooks * return the stored name (if valid or invalid match). 258241233Sbrooks * We use a simple hash table. 259241233Sbrooks * Return 260241233Sbrooks * Pointer to stored name (or a empty string) 261241233Sbrooks */ 262241233Sbrooksconst char * 263241233Sbrooksuser_from_uid(uid_t uid, int noname) 264241233Sbrooks{ 265241233Sbrooks struct passwd *pw; 266241233Sbrooks UIDC *ptr, **pptr; 267241233Sbrooks 268241233Sbrooks if ((uidtb == NULL) && (uidtb_start() < 0)) 269241233Sbrooks return (NULL); 270241233Sbrooks 271241233Sbrooks /* 272241233Sbrooks * see if we have this uid cached 273241233Sbrooks */ 274241233Sbrooks pptr = uidtb + (uid % UID_SZ); 275241233Sbrooks ptr = *pptr; 276241233Sbrooks 277241233Sbrooks if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { 278241233Sbrooks /* 279241233Sbrooks * have an entry for this uid 280241233Sbrooks */ 281241233Sbrooks if (!noname || (ptr->valid == VALID)) 282241233Sbrooks return (ptr->name); 283241233Sbrooks return (NULL); 284241233Sbrooks } 285241233Sbrooks 286241233Sbrooks /* 287241233Sbrooks * No entry for this uid, we will add it 288241233Sbrooks */ 289241233Sbrooks if (!pwopn) { 290241233Sbrooks if (_pwcache_setpassent != NULL) 291241233Sbrooks (*_pwcache_setpassent)(1); 292241233Sbrooks ++pwopn; 293241233Sbrooks } 294241233Sbrooks 295241233Sbrooks if (ptr == NULL) 296241233Sbrooks *pptr = ptr = (UIDC *)malloc(sizeof(UIDC)); 297241233Sbrooks 298241233Sbrooks if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) { 299241233Sbrooks /* 300241233Sbrooks * no match for this uid in the local password file 301241233Sbrooks * a string that is the uid in numeric format 302241233Sbrooks */ 303241233Sbrooks if (ptr == NULL) 304241233Sbrooks return (NULL); 305241233Sbrooks ptr->uid = uid; 306241233Sbrooks (void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid); 307241233Sbrooks ptr->valid = INVALID; 308241233Sbrooks if (noname) 309241233Sbrooks return (NULL); 310241233Sbrooks } else { 311241233Sbrooks /* 312241233Sbrooks * there is an entry for this uid in the password file 313241233Sbrooks */ 314241233Sbrooks if (ptr == NULL) 315241233Sbrooks return (pw->pw_name); 316241233Sbrooks ptr->uid = uid; 317241233Sbrooks (void)strlcpy(ptr->name, pw->pw_name, UNMLEN); 318241233Sbrooks ptr->valid = VALID; 319241233Sbrooks } 320241233Sbrooks return (ptr->name); 321241233Sbrooks} 322241233Sbrooks 323241233Sbrooks/* 324241233Sbrooks * group_from_gid() 325241233Sbrooks * caches the name (if any) for the gid. If noname clear, we always 326241233Sbrooks * return the stored name (if valid or invalid match). 327241233Sbrooks * We use a simple hash table. 328241233Sbrooks * Return 329241233Sbrooks * Pointer to stored name (or a empty string) 330241233Sbrooks */ 331241233Sbrooksconst char * 332241233Sbrooksgroup_from_gid(gid_t gid, int noname) 333241233Sbrooks{ 334241233Sbrooks struct group *gr; 335241233Sbrooks GIDC *ptr, **pptr; 336241233Sbrooks 337241233Sbrooks if ((gidtb == NULL) && (gidtb_start() < 0)) 338241233Sbrooks return (NULL); 339241233Sbrooks 340241233Sbrooks /* 341241233Sbrooks * see if we have this gid cached 342241233Sbrooks */ 343241233Sbrooks pptr = gidtb + (gid % GID_SZ); 344241233Sbrooks ptr = *pptr; 345241233Sbrooks 346241233Sbrooks if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { 347241233Sbrooks /* 348241233Sbrooks * have an entry for this gid 349241233Sbrooks */ 350241233Sbrooks if (!noname || (ptr->valid == VALID)) 351241233Sbrooks return (ptr->name); 352241233Sbrooks return (NULL); 353241233Sbrooks } 354241233Sbrooks 355241233Sbrooks /* 356241233Sbrooks * No entry for this gid, we will add it 357241233Sbrooks */ 358241233Sbrooks if (!gropn) { 359241233Sbrooks if (_pwcache_setgroupent != NULL) 360241233Sbrooks (*_pwcache_setgroupent)(1); 361241233Sbrooks ++gropn; 362241233Sbrooks } 363241233Sbrooks 364241233Sbrooks if (ptr == NULL) 365241233Sbrooks *pptr = ptr = (GIDC *)malloc(sizeof(GIDC)); 366241233Sbrooks 367241233Sbrooks if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) { 368241233Sbrooks /* 369241233Sbrooks * no match for this gid in the local group file, put in 370241233Sbrooks * a string that is the gid in numberic format 371241233Sbrooks */ 372241233Sbrooks if (ptr == NULL) 373241233Sbrooks return (NULL); 374241233Sbrooks ptr->gid = gid; 375241233Sbrooks (void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid); 376241233Sbrooks ptr->valid = INVALID; 377241233Sbrooks if (noname) 378241233Sbrooks return (NULL); 379241233Sbrooks } else { 380241233Sbrooks /* 381241233Sbrooks * there is an entry for this group in the group file 382241233Sbrooks */ 383241233Sbrooks if (ptr == NULL) 384241233Sbrooks return (gr->gr_name); 385241233Sbrooks ptr->gid = gid; 386241233Sbrooks (void)strlcpy(ptr->name, gr->gr_name, GNMLEN); 387241233Sbrooks ptr->valid = VALID; 388241233Sbrooks } 389241233Sbrooks return (ptr->name); 390241233Sbrooks} 391241233Sbrooks 392241233Sbrooks/* 393241233Sbrooks * uid_from_user() 394241233Sbrooks * caches the uid for a given user name. We use a simple hash table. 395241233Sbrooks * Return 396241233Sbrooks * the uid (if any) for a user name, or a -1 if no match can be found 397241233Sbrooks */ 398241233Sbrooksint 399241233Sbrooksuid_from_user(const char *name, uid_t *uid) 400241233Sbrooks{ 401241233Sbrooks struct passwd *pw; 402241233Sbrooks UIDC *ptr, **pptr; 403241233Sbrooks size_t namelen; 404241233Sbrooks 405241233Sbrooks /* 406241233Sbrooks * return -1 for mangled names 407241233Sbrooks */ 408241233Sbrooks if (name == NULL || ((namelen = strlen(name)) == 0)) 409241233Sbrooks return (-1); 410241233Sbrooks if ((usrtb == NULL) && (usrtb_start() < 0)) 411241233Sbrooks return (-1); 412241233Sbrooks 413241233Sbrooks /* 414241233Sbrooks * look up in hash table, if found and valid return the uid, 415241233Sbrooks * if found and invalid, return a -1 416241233Sbrooks */ 417241233Sbrooks pptr = usrtb + st_hash(name, namelen, UNM_SZ); 418241233Sbrooks ptr = *pptr; 419241233Sbrooks 420241233Sbrooks if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 421241233Sbrooks if (ptr->valid == INVALID) 422241233Sbrooks return (-1); 423241233Sbrooks *uid = ptr->uid; 424241233Sbrooks return (0); 425241233Sbrooks } 426241233Sbrooks 427241233Sbrooks if (!pwopn) { 428241233Sbrooks if (_pwcache_setpassent != NULL) 429241233Sbrooks (*_pwcache_setpassent)(1); 430241233Sbrooks ++pwopn; 431241233Sbrooks } 432241233Sbrooks 433241233Sbrooks if (ptr == NULL) 434241233Sbrooks *pptr = ptr = (UIDC *)malloc(sizeof(UIDC)); 435241233Sbrooks 436241233Sbrooks /* 437241233Sbrooks * no match, look it up, if no match store it as an invalid entry, 438241233Sbrooks * or store the matching uid 439241233Sbrooks */ 440241233Sbrooks if (ptr == NULL) { 441241233Sbrooks if ((pw = (*_pwcache_getpwnam)(name)) == NULL) 442241233Sbrooks return (-1); 443241233Sbrooks *uid = pw->pw_uid; 444241233Sbrooks return (0); 445241233Sbrooks } 446241233Sbrooks (void)strlcpy(ptr->name, name, UNMLEN); 447241233Sbrooks if ((pw = (*_pwcache_getpwnam)(name)) == NULL) { 448241233Sbrooks ptr->valid = INVALID; 449241233Sbrooks return (-1); 450241233Sbrooks } 451241233Sbrooks ptr->valid = VALID; 452241233Sbrooks *uid = ptr->uid = pw->pw_uid; 453241233Sbrooks return (0); 454241233Sbrooks} 455241233Sbrooks 456241233Sbrooks/* 457241233Sbrooks * gid_from_group() 458241233Sbrooks * caches the gid for a given group name. We use a simple hash table. 459241233Sbrooks * Return 460241233Sbrooks * the gid (if any) for a group name, or a -1 if no match can be found 461241233Sbrooks */ 462241233Sbrooksint 463241233Sbrooksgid_from_group(const char *name, gid_t *gid) 464241233Sbrooks{ 465241233Sbrooks struct group *gr; 466241233Sbrooks GIDC *ptr, **pptr; 467241233Sbrooks size_t namelen; 468241233Sbrooks 469241233Sbrooks /* 470241233Sbrooks * return -1 for mangled names 471241233Sbrooks */ 472241233Sbrooks if (name == NULL || ((namelen = strlen(name)) == 0)) 473241233Sbrooks return (-1); 474241233Sbrooks if ((grptb == NULL) && (grptb_start() < 0)) 475241233Sbrooks return (-1); 476241233Sbrooks 477241233Sbrooks /* 478241233Sbrooks * look up in hash table, if found and valid return the uid, 479241233Sbrooks * if found and invalid, return a -1 480241233Sbrooks */ 481241233Sbrooks pptr = grptb + st_hash(name, namelen, GID_SZ); 482241233Sbrooks ptr = *pptr; 483241233Sbrooks 484241233Sbrooks if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { 485241233Sbrooks if (ptr->valid == INVALID) 486241233Sbrooks return (-1); 487241233Sbrooks *gid = ptr->gid; 488241233Sbrooks return (0); 489241233Sbrooks } 490241233Sbrooks 491241233Sbrooks if (!gropn) { 492241233Sbrooks if (_pwcache_setgroupent != NULL) 493241233Sbrooks (*_pwcache_setgroupent)(1); 494241233Sbrooks ++gropn; 495241233Sbrooks } 496241233Sbrooks 497241233Sbrooks if (ptr == NULL) 498241233Sbrooks *pptr = ptr = (GIDC *)malloc(sizeof(GIDC)); 499241233Sbrooks 500241233Sbrooks /* 501241233Sbrooks * no match, look it up, if no match store it as an invalid entry, 502241233Sbrooks * or store the matching gid 503241233Sbrooks */ 504241233Sbrooks if (ptr == NULL) { 505241233Sbrooks if ((gr = (*_pwcache_getgrnam)(name)) == NULL) 506241233Sbrooks return (-1); 507241233Sbrooks *gid = gr->gr_gid; 508241233Sbrooks return (0); 509241233Sbrooks } 510241233Sbrooks 511241233Sbrooks (void)strlcpy(ptr->name, name, GNMLEN); 512241233Sbrooks if ((gr = (*_pwcache_getgrnam)(name)) == NULL) { 513241233Sbrooks ptr->valid = INVALID; 514241233Sbrooks return (-1); 515241233Sbrooks } 516241233Sbrooks ptr->valid = VALID; 517241233Sbrooks *gid = ptr->gid = gr->gr_gid; 518241233Sbrooks return (0); 519241233Sbrooks} 520241233Sbrooks 521241233Sbrooks#define FLUSHTB(arr, len, fail) \ 522241233Sbrooks do { \ 523241233Sbrooks if (arr != NULL) { \ 524241233Sbrooks for (i = 0; i < len; i++) \ 525241233Sbrooks if (arr[i] != NULL) \ 526241233Sbrooks free(arr[i]); \ 527241233Sbrooks arr = NULL; \ 528241233Sbrooks } \ 529241233Sbrooks fail = 0; \ 530241233Sbrooks } while (/* CONSTCOND */0); 531241233Sbrooks 532241233Sbrooksint 533241233Sbrookspwcache_userdb( 534241233Sbrooks int (*a_setpassent)(int), 535241233Sbrooks void (*a_endpwent)(void), 536241233Sbrooks struct passwd * (*a_getpwnam)(const char *), 537241233Sbrooks struct passwd * (*a_getpwuid)(uid_t)) 538241233Sbrooks{ 539241233Sbrooks int i; 540241233Sbrooks 541241233Sbrooks /* a_setpassent and a_endpwent may be NULL */ 542241233Sbrooks if (a_getpwnam == NULL || a_getpwuid == NULL) 543241233Sbrooks return (-1); 544241233Sbrooks 545241233Sbrooks if (_pwcache_endpwent != NULL) 546241233Sbrooks (*_pwcache_endpwent)(); 547241233Sbrooks FLUSHTB(uidtb, UID_SZ, uidtb_fail); 548241233Sbrooks FLUSHTB(usrtb, UNM_SZ, usrtb_fail); 549241233Sbrooks pwopn = 0; 550241233Sbrooks _pwcache_setpassent = a_setpassent; 551241233Sbrooks _pwcache_endpwent = a_endpwent; 552241233Sbrooks _pwcache_getpwnam = a_getpwnam; 553241233Sbrooks _pwcache_getpwuid = a_getpwuid; 554241233Sbrooks 555241233Sbrooks return (0); 556241233Sbrooks} 557241233Sbrooks 558241233Sbrooksint 559241233Sbrookspwcache_groupdb( 560241233Sbrooks int (*a_setgroupent)(int), 561241233Sbrooks void (*a_endgrent)(void), 562241233Sbrooks struct group * (*a_getgrnam)(const char *), 563241233Sbrooks struct group * (*a_getgrgid)(gid_t)) 564241233Sbrooks{ 565241233Sbrooks int i; 566241233Sbrooks 567241233Sbrooks /* a_setgroupent and a_endgrent may be NULL */ 568241233Sbrooks if (a_getgrnam == NULL || a_getgrgid == NULL) 569241233Sbrooks return (-1); 570241233Sbrooks 571241233Sbrooks if (_pwcache_endgrent != NULL) 572241233Sbrooks (*_pwcache_endgrent)(); 573241233Sbrooks FLUSHTB(gidtb, GID_SZ, gidtb_fail); 574241233Sbrooks FLUSHTB(grptb, GNM_SZ, grptb_fail); 575241233Sbrooks gropn = 0; 576241233Sbrooks _pwcache_setgroupent = a_setgroupent; 577241233Sbrooks _pwcache_endgrent = a_endgrent; 578241233Sbrooks _pwcache_getgrnam = a_getgrnam; 579241233Sbrooks _pwcache_getgrgid = a_getgrgid; 580241233Sbrooks 581241233Sbrooks return (0); 582241233Sbrooks} 583241233Sbrooks 584241233Sbrooks 585241233Sbrooks#ifdef TEST_PWCACHE 586241233Sbrooks 587241233Sbrooksstruct passwd * 588241233Sbrookstest_getpwnam(const char *name) 589241233Sbrooks{ 590241233Sbrooks static struct passwd foo; 591241233Sbrooks 592241233Sbrooks memset(&foo, 0, sizeof(foo)); 593241233Sbrooks if (strcmp(name, "toor") == 0) { 594241233Sbrooks foo.pw_uid = 666; 595241233Sbrooks return &foo; 596241233Sbrooks } 597241233Sbrooks return (getpwnam(name)); 598241233Sbrooks} 599241233Sbrooks 600241233Sbrooksint 601241233Sbrooksmain(int argc, char *argv[]) 602241233Sbrooks{ 603241233Sbrooks uid_t u; 604241233Sbrooks int r, i; 605241233Sbrooks 606241233Sbrooks printf("pass 1 (default userdb)\n"); 607241233Sbrooks for (i = 1; i < argc; i++) { 608241233Sbrooks printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n", 609241233Sbrooks i, pwopn, usrtb_fail, usrtb); 610241233Sbrooks r = uid_from_user(argv[i], &u); 611241233Sbrooks if (r == -1) 612241233Sbrooks printf(" uid_from_user %s: failed\n", argv[i]); 613241233Sbrooks else 614241233Sbrooks printf(" uid_from_user %s: %d\n", argv[i], u); 615241233Sbrooks } 616241233Sbrooks printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n", 617241233Sbrooks pwopn, usrtb_fail, usrtb); 618241233Sbrooks 619241233Sbrooks puts(""); 620241233Sbrooks printf("pass 2 (replacement userdb)\n"); 621241233Sbrooks printf("pwcache_userdb returned %d\n", 622241233Sbrooks pwcache_userdb(setpassent, test_getpwnam, getpwuid)); 623241233Sbrooks printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb); 624241233Sbrooks 625241233Sbrooks for (i = 1; i < argc; i++) { 626241233Sbrooks printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n", 627241233Sbrooks i, pwopn, usrtb_fail, usrtb); 628241233Sbrooks u = -1; 629241233Sbrooks r = uid_from_user(argv[i], &u); 630241233Sbrooks if (r == -1) 631241233Sbrooks printf(" uid_from_user %s: failed\n", argv[i]); 632241233Sbrooks else 633241233Sbrooks printf(" uid_from_user %s: %d\n", argv[i], u); 634241233Sbrooks } 635241233Sbrooks printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n", 636241233Sbrooks pwopn, usrtb_fail, usrtb); 637241233Sbrooks 638241233Sbrooks puts(""); 639241233Sbrooks printf("pass 3 (null pointers)\n"); 640241233Sbrooks printf("pwcache_userdb returned %d\n", 641241233Sbrooks pwcache_userdb(NULL, NULL, NULL)); 642241233Sbrooks 643241233Sbrooks return (0); 644241233Sbrooks} 645241233Sbrooks#endif /* TEST_PWCACHE */ 646241233Sbrooks#endif /* !HAVE_PWCACHE_USERDB */ 647