165532Snectar/* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */ 265532Snectar 365532Snectar/*- 465532Snectar * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc. 565532Snectar * All rights reserved. 665532Snectar * 765532Snectar * This code is derived from software contributed to The NetBSD Foundation 865532Snectar * by Luke Mewburn. 965532Snectar * 1065532Snectar * Redistribution and use in source and binary forms, with or without 1165532Snectar * modification, are permitted provided that the following conditions 1265532Snectar * are met: 1365532Snectar * 1. Redistributions of source code must retain the above copyright 1465532Snectar * notice, this list of conditions and the following disclaimer. 1565532Snectar * 2. Redistributions in binary form must reproduce the above copyright 1665532Snectar * notice, this list of conditions and the following disclaimer in the 1765532Snectar * documentation and/or other materials provided with the distribution. 1865532Snectar * 1965532Snectar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2065532Snectar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2165532Snectar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2265532Snectar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2365532Snectar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2465532Snectar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2565532Snectar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2665532Snectar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2765532Snectar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2865532Snectar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2965532Snectar * POSSIBILITY OF SUCH DAMAGE. 3065532Snectar */ 31113595Snectar/*- 32113595Snectar * Copyright (c) 2003 Networks Associates Technology, Inc. 33113595Snectar * All rights reserved. 34113595Snectar * 35113595Snectar * Portions of this software were developed for the FreeBSD Project by 36113595Snectar * Jacques A. Vidrine, Safeport Network Services, and Network 37113595Snectar * Associates Laboratories, the Security Research Division of Network 38113595Snectar * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 39113595Snectar * ("CBOSS"), as part of the DARPA CHATS research program. 40113595Snectar * 41113595Snectar * Redistribution and use in source and binary forms, with or without 42113595Snectar * modification, are permitted provided that the following conditions 43113595Snectar * are met: 44113595Snectar * 1. Redistributions of source code must retain the above copyright 45113595Snectar * notice, this list of conditions and the following disclaimer. 46113595Snectar * 2. Redistributions in binary form must reproduce the above copyright 47113595Snectar * notice, this list of conditions and the following disclaimer in the 48113595Snectar * documentation and/or other materials provided with the distribution. 49113595Snectar * 50113595Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 51113595Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52113595Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53113595Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 54113595Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55113595Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56113595Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57113595Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58113595Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59113595Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60113595Snectar * SUCH DAMAGE. 61113595Snectar * 62113595Snectar */ 6365532Snectar#include <sys/cdefs.h> 6492986Sobrien__FBSDID("$FreeBSD$"); 6565532Snectar 66113595Snectar#include "namespace.h" 6765532Snectar#include <sys/param.h> 6865532Snectar#include <sys/stat.h> 6965532Snectar 70113595Snectar#include <dlfcn.h> 71113595Snectar#include <errno.h> 7265532Snectar#include <fcntl.h> 7365532Snectar#define _NS_PRIVATE 7465532Snectar#include <nsswitch.h> 75113595Snectar#include <pthread.h> 76192911Szml#include <pthread_np.h> 7765532Snectar#include <stdio.h> 7865532Snectar#include <stdlib.h> 7965532Snectar#include <string.h> 80113595Snectar#include <syslog.h> 8165532Snectar#include <unistd.h> 82111618Snectar#include "un-namespace.h" 83192911Szml#include "nss_tls.h" 84178720Sjhb#include "libc_private.h" 85158115Sume#ifdef NS_CACHING 86158115Sume#include "nscache.h" 87158115Sume#endif 8865532Snectar 89113595Snectarenum _nss_constants { 90113595Snectar /* Number of elements allocated when we grow a vector */ 91113595Snectar ELEMSPERCHUNK = 8 92113595Snectar}; 93113595Snectar 9465532Snectar/* 95113595Snectar * Global NSS data structures are mostly read-only, but we update 96113595Snectar * them when we read or re-read the nsswitch.conf. 97113595Snectar */ 98113595Snectarstatic pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; 99113595Snectar 100113595Snectar/* 101113595Snectar * Runtime determination of whether we are dynamically linked or not. 102113595Snectar */ 103113595Snectarextern int _DYNAMIC __attribute__ ((weak)); 104113595Snectar#define is_dynamic() (&_DYNAMIC != NULL) 105113595Snectar 106113595Snectar/* 10765532Snectar * default sourcelist: `files' 10865532Snectar */ 10965532Snectarconst ns_src __nsdefaultsrc[] = { 11065532Snectar { NSSRC_FILES, NS_SUCCESS }, 11165532Snectar { 0 }, 11265532Snectar}; 11365532Snectar 114113595Snectar/* Database, source mappings. */ 115113595Snectarstatic unsigned int _nsmapsize; 11665532Snectarstatic ns_dbt *_nsmap = NULL; 11765532Snectar 118113595Snectar/* NSS modules. */ 119113595Snectarstatic unsigned int _nsmodsize; 120113595Snectarstatic ns_mod *_nsmod; 121113595Snectar 122113595Snectar/* Placeholder for builtin modules' dlopen `handle'. */ 123113595Snectarstatic int __nss_builtin_handle; 124113595Snectarstatic void *nss_builtin_handle = &__nss_builtin_handle; 125113595Snectar 126158115Sume#ifdef NS_CACHING 12765532Snectar/* 128158115Sume * Cache lookup cycle prevention function - if !NULL then no cache lookups 129158115Sume * will be made 130158115Sume */ 131158115Sumestatic void *nss_cache_cycle_prevention_func = NULL; 132158115Sume#endif 133158115Sume 134158115Sume/* 135174547Sbushman * When this is set to 1, nsdispatch won't use nsswitch.conf 136174547Sbushman * but will consult the 'defaults' source list only. 137174547Sbushman * NOTE: nested fallbacks (when nsdispatch calls fallback functions, 138174547Sbushman * which in turn calls nsdispatch, which should call fallback 139174547Sbushman * function) are not supported 140174547Sbushman */ 141192911Szmlstruct fb_state { 142192911Szml int fb_dispatch; 143192911Szml}; 144192911Szmlstatic void fb_endstate(void *); 145192911SzmlNSS_TLS_HANDLING(fb); 146174547Sbushman 147174547Sbushman/* 148113595Snectar * Attempt to spew relatively uniform messages to syslog. 14965532Snectar */ 150113595Snectar#define nss_log(level, fmt, ...) \ 151113595Snectar syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__) 152113595Snectar#define nss_log_simple(level, s) \ 153113595Snectar syslog((level), "NSSWITCH(%s): " s, __func__) 15465532Snectar 155113595Snectar/* 156113595Snectar * Dynamically growable arrays are used for lists of databases, sources, 157113595Snectar * and modules. The following `vector' interface is used to isolate the 158113595Snectar * common operations. 159113595Snectar */ 160113595Snectartypedef int (*vector_comparison)(const void *, const void *); 161113595Snectartypedef void (*vector_free_elem)(void *); 162113595Snectarstatic void vector_sort(void *, unsigned int, size_t, 163113595Snectar vector_comparison); 164127012Sdesstatic void vector_free(void *, unsigned int *, size_t, 165113595Snectar vector_free_elem); 166113595Snectarstatic void *vector_ref(unsigned int, void *, unsigned int, size_t); 167113595Snectarstatic void *vector_search(const void *, void *, unsigned int, size_t, 168113595Snectar vector_comparison); 169127012Sdesstatic void *vector_append(const void *, void *, unsigned int *, size_t); 17065532Snectar 17165532Snectar 172113595Snectar/* 173113595Snectar * Internal interfaces. 174113595Snectar */ 175113595Snectarstatic int string_compare(const void *, const void *); 176113595Snectarstatic int mtab_compare(const void *, const void *); 177113595Snectarstatic int nss_configure(void); 178113595Snectarstatic void ns_dbt_free(ns_dbt *); 179113595Snectarstatic void ns_mod_free(ns_mod *); 180113595Snectarstatic void ns_src_free(ns_src **, int); 181113595Snectarstatic void nss_load_builtin_modules(void); 182113595Snectarstatic void nss_load_module(const char *, nss_module_register_fn); 183113595Snectarstatic void nss_atexit(void); 184113595Snectar/* nsparser */ 185113595Snectarextern FILE *_nsyyin; 18665532Snectar 187113595Snectar 188113595Snectar/* 189113595Snectar * The vector operations 190113595Snectar */ 191113595Snectarstatic void 192113595Snectarvector_sort(void *vec, unsigned int count, size_t esize, 193113595Snectar vector_comparison comparison) 19465532Snectar{ 195113595Snectar qsort(vec, count, esize, comparison); 19665532Snectar} 19765532Snectar 19865532Snectar 199113595Snectarstatic void * 200113595Snectarvector_search(const void *key, void *vec, unsigned int count, size_t esize, 201113595Snectar vector_comparison comparison) 20265532Snectar{ 203113595Snectar return (bsearch(key, vec, count, esize, comparison)); 204113595Snectar} 205113595Snectar 206113595Snectar 207127012Sdesstatic void * 208127012Sdesvector_append(const void *elem, void *vec, unsigned int *count, size_t esize) 209113595Snectar{ 210113595Snectar void *p; 211113595Snectar 212113595Snectar if ((*count % ELEMSPERCHUNK) == 0) { 213127012Sdes p = realloc(vec, (*count + ELEMSPERCHUNK) * esize); 214113595Snectar if (p == NULL) { 215113595Snectar nss_log_simple(LOG_ERR, "memory allocation failure"); 216127012Sdes return (vec); 217127012Sdes } 218127012Sdes vec = p; 21965532Snectar } 220127012Sdes memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize); 221113595Snectar (*count)++; 222127012Sdes return (vec); 22365532Snectar} 22465532Snectar 22565532Snectar 226113595Snectarstatic void * 227113595Snectarvector_ref(unsigned int i, void *vec, unsigned int count, size_t esize) 228113595Snectar{ 229113595Snectar if (i < count) 230113595Snectar return (void *)((uintptr_t)vec + (i * esize)); 231113595Snectar else 232113595Snectar return (NULL); 233113595Snectar} 234113595Snectar 235113595Snectar 236127012Sdes#define VECTOR_FREE(v, c, s, f) \ 237127012Sdes do { vector_free(v, c, s, f); v = NULL; } while (0) 238113595Snectarstatic void 239127012Sdesvector_free(void *vec, unsigned int *count, size_t esize, 240113595Snectar vector_free_elem free_elem) 241113595Snectar{ 242113595Snectar unsigned int i; 243113595Snectar void *elem; 244113595Snectar 245113595Snectar for (i = 0; i < *count; i++) { 246127012Sdes elem = vector_ref(i, vec, *count, esize); 247113595Snectar if (elem != NULL) 248113595Snectar free_elem(elem); 249113595Snectar } 250127012Sdes free(vec); 251113595Snectar *count = 0; 252113595Snectar} 253113595Snectar 254113595Snectar/* 255113595Snectar * Comparison functions for vector_search. 256113595Snectar */ 257113595Snectarstatic int 258113595Snectarstring_compare(const void *a, const void *b) 259113595Snectar{ 260113595Snectar return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); 261113595Snectar} 262113595Snectar 263113595Snectar 264113595Snectarstatic int 265113595Snectarmtab_compare(const void *a, const void *b) 266113595Snectar{ 267113595Snectar int cmp; 268127011Sdes 269113595Snectar cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name); 270113595Snectar if (cmp != 0) 271113595Snectar return (cmp); 272113595Snectar else 273113595Snectar return (strcmp(((const ns_mtab *)a)->database, 274113595Snectar ((const ns_mtab *)b)->database)); 275113595Snectar} 276113595Snectar 277113595Snectar/* 278113595Snectar * NSS nsmap management. 279113595Snectar */ 28065532Snectarvoid 281113595Snectar_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src) 28265532Snectar{ 283113595Snectar const ns_mod *modp; 284113595Snectar 285127012Sdes dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize, 286113595Snectar sizeof(*src)); 287113595Snectar modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod), 288113595Snectar string_compare); 289113595Snectar if (modp == NULL) 290113595Snectar nss_load_module(src->name, NULL); 291113595Snectar} 292113595Snectar 293113595Snectar 294113595Snectar#ifdef _NSS_DEBUG 295113595Snectarvoid 296113595Snectar_nsdbtdump(const ns_dbt *dbt) 297113595Snectar{ 29865532Snectar int i; 29965532Snectar 30065532Snectar printf("%s (%d source%s):", dbt->name, dbt->srclistsize, 30165532Snectar dbt->srclistsize == 1 ? "" : "s"); 302113595Snectar for (i = 0; i < (int)dbt->srclistsize; i++) { 30365532Snectar printf(" %s", dbt->srclist[i].name); 30465532Snectar if (!(dbt->srclist[i].flags & 30565532Snectar (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) && 30665532Snectar (dbt->srclist[i].flags & NS_SUCCESS)) 30765532Snectar continue; 30865532Snectar printf(" ["); 30965532Snectar if (!(dbt->srclist[i].flags & NS_SUCCESS)) 31065532Snectar printf(" SUCCESS=continue"); 31165532Snectar if (dbt->srclist[i].flags & NS_UNAVAIL) 31265532Snectar printf(" UNAVAIL=return"); 31365532Snectar if (dbt->srclist[i].flags & NS_NOTFOUND) 31465532Snectar printf(" NOTFOUND=return"); 31565532Snectar if (dbt->srclist[i].flags & NS_TRYAGAIN) 31665532Snectar printf(" TRYAGAIN=return"); 31765532Snectar printf(" ]"); 31865532Snectar } 31965532Snectar printf("\n"); 32065532Snectar} 321113595Snectar#endif 32265532Snectar 32365532Snectar 324127011Sdes/* 325113595Snectar * The first time nsdispatch is called (during a process's lifetime, 326113595Snectar * or after nsswitch.conf has been updated), nss_configure will 327113595Snectar * prepare global data needed by NSS. 328113595Snectar */ 329113595Snectarstatic int 330113595Snectarnss_configure(void) 33165532Snectar{ 332113595Snectar static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER; 333113595Snectar static time_t confmod; 33465532Snectar struct stat statbuf; 335127625Snectar int result, isthreaded; 336113595Snectar const char *path; 337158115Sume#ifdef NS_CACHING 338158115Sume void *handle; 339158115Sume#endif 34065532Snectar 341127625Snectar result = 0; 342127625Snectar isthreaded = __isthreaded; 343113595Snectar#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT) 344113595Snectar /* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built 345113595Snectar * for debugging purposes and MUST NEVER be used in production. 346113595Snectar */ 347113595Snectar path = getenv("NSSWITCH_CONF"); 348113595Snectar if (path == NULL) 349113595Snectar#endif 350113595Snectar path = _PATH_NS_CONF; 351113595Snectar if (stat(path, &statbuf) != 0) 352113595Snectar return (0); 353113595Snectar if (statbuf.st_mtime <= confmod) 354113595Snectar return (0); 355127625Snectar if (isthreaded) { 356127625Snectar result = _pthread_mutex_trylock(&conf_lock); 357127625Snectar if (result != 0) 358127625Snectar return (0); 359127625Snectar (void)_pthread_rwlock_unlock(&nss_lock); 360127625Snectar result = _pthread_rwlock_wrlock(&nss_lock); 361127625Snectar if (result != 0) 362127625Snectar goto fin2; 363127625Snectar } 364254700Sjilles _nsyyin = fopen(path, "re"); 365127727Snectar if (_nsyyin == NULL) 366113595Snectar goto fin; 367127012Sdes VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 368113595Snectar (vector_free_elem)ns_dbt_free); 369127012Sdes VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 370113595Snectar (vector_free_elem)ns_mod_free); 371113595Snectar nss_load_builtin_modules(); 372113595Snectar _nsyyparse(); 373113595Snectar (void)fclose(_nsyyin); 374113595Snectar vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare); 375113595Snectar if (confmod == 0) 376113595Snectar (void)atexit(nss_atexit); 377113595Snectar confmod = statbuf.st_mtime; 378158115Sume 379158115Sume#ifdef NS_CACHING 380228843Scperciva handle = libc_dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); 381158115Sume if (handle != NULL) { 382158115Sume nss_cache_cycle_prevention_func = dlsym(handle, 383158115Sume "_nss_cache_cycle_prevention_function"); 384158115Sume dlclose(handle); 385158115Sume } 386158115Sume#endif 387113595Snectarfin: 388127625Snectar if (isthreaded) { 389127625Snectar (void)_pthread_rwlock_unlock(&nss_lock); 390127625Snectar if (result == 0) 391127625Snectar result = _pthread_rwlock_rdlock(&nss_lock); 392127625Snectar } 393113595Snectarfin2: 394127625Snectar if (isthreaded) 395127625Snectar (void)_pthread_mutex_unlock(&conf_lock); 396113595Snectar return (result); 397113595Snectar} 39865532Snectar 39965532Snectar 400113595Snectarvoid 401113595Snectar_nsdbtput(const ns_dbt *dbt) 402113595Snectar{ 403113595Snectar unsigned int i; 404113595Snectar ns_dbt *p; 40565532Snectar 406113595Snectar for (i = 0; i < _nsmapsize; i++) { 407113595Snectar p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap)); 408113595Snectar if (string_compare(&dbt->name, &p->name) == 0) { 409113595Snectar /* overwrite existing entry */ 410113595Snectar if (p->srclist != NULL) 411113595Snectar ns_src_free(&p->srclist, p->srclistsize); 412113595Snectar memmove(p, dbt, sizeof(*dbt)); 413113595Snectar return; 41465532Snectar } 41565532Snectar } 416127012Sdes _nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap)); 41765532Snectar} 41865532Snectar 41965532Snectar 420113595Snectarstatic void 421113595Snectarns_dbt_free(ns_dbt *dbt) 42265532Snectar{ 423113595Snectar ns_src_free(&dbt->srclist, dbt->srclistsize); 424169644Sjon if (dbt->name) 425169644Sjon free((void *)dbt->name); 426113595Snectar} 427113595Snectar 428113595Snectar 429113595Snectarstatic void 430113595Snectarns_src_free(ns_src **src, int srclistsize) 431113595Snectar{ 43265532Snectar int i; 43365532Snectar 434113595Snectar for (i = 0; i < srclistsize; i++) 435113595Snectar if ((*src)[i].name != NULL) 436113595Snectar /* This one was allocated by nslexer. You'll just 437113595Snectar * have to trust me. 438113595Snectar */ 439113595Snectar free((void *)((*src)[i].name)); 440113595Snectar free(*src); 441113595Snectar *src = NULL; 442113595Snectar} 443113595Snectar 444113595Snectar 445113595Snectar 446113595Snectar/* 447113595Snectar * NSS module management. 448113595Snectar */ 449113595Snectar/* The built-in NSS modules are all loaded at once. */ 450113595Snectar#define NSS_BACKEND(name, reg) \ 451113595Snectarns_mtab *reg(unsigned int *, nss_module_unregister_fn *); 452113595Snectar#include "nss_backends.h" 453113595Snectar#undef NSS_BACKEND 454113595Snectar 455113595Snectarstatic void 456113595Snectarnss_load_builtin_modules(void) 457113595Snectar{ 458113595Snectar#define NSS_BACKEND(name, reg) nss_load_module(#name, reg); 459113595Snectar#include "nss_backends.h" 460113595Snectar#undef NSS_BACKEND 461113595Snectar} 462113595Snectar 463113595Snectar 464113595Snectar/* Load a built-in or dynamically linked module. If the `reg_fn' 465113595Snectar * argument is non-NULL, assume a built-in module and use reg_fn to 466113595Snectar * register it. Otherwise, search for a dynamic NSS module. 467113595Snectar */ 468113595Snectarstatic void 469113595Snectarnss_load_module(const char *source, nss_module_register_fn reg_fn) 470113595Snectar{ 471113595Snectar char buf[PATH_MAX]; 472113595Snectar ns_mod mod; 473113595Snectar nss_module_register_fn fn; 474127011Sdes 475113595Snectar memset(&mod, 0, sizeof(mod)); 476113595Snectar mod.name = strdup(source); 477113595Snectar if (mod.name == NULL) { 478113595Snectar nss_log_simple(LOG_ERR, "memory allocation failure"); 479113595Snectar return; 480113595Snectar } 481113595Snectar if (reg_fn != NULL) { 482127011Sdes /* The placeholder is required, as a NULL handle 483113595Snectar * represents an invalid module. 484113595Snectar */ 485113595Snectar mod.handle = nss_builtin_handle; 486113595Snectar fn = reg_fn; 487113595Snectar } else if (!is_dynamic()) 488113595Snectar goto fin; 489113595Snectar else { 490113595Snectar if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name, 491113595Snectar NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf)) 492113595Snectar goto fin; 493228843Scperciva mod.handle = libc_dlopen(buf, RTLD_LOCAL|RTLD_LAZY); 494113595Snectar if (mod.handle == NULL) { 495113595Snectar#ifdef _NSS_DEBUG 496113595Snectar /* This gets pretty annoying since the built-in 497113595Snectar * sources aren't modules yet. 498113595Snectar */ 499113595Snectar nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror()); 500113595Snectar#endif 501113595Snectar goto fin; 50265532Snectar } 503113595Snectar fn = (nss_module_register_fn)dlfunc(mod.handle, 504113595Snectar "nss_module_register"); 505113595Snectar if (fn == NULL) { 506113595Snectar (void)dlclose(mod.handle); 507113595Snectar mod.handle = NULL; 508113595Snectar nss_log(LOG_ERR, "%s, %s", mod.name, dlerror()); 509113595Snectar goto fin; 510113595Snectar } 51165532Snectar } 512113595Snectar mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister); 513113595Snectar if (mod.mtab == NULL || mod.mtabsize == 0) { 514113595Snectar if (mod.handle != nss_builtin_handle) 515113595Snectar (void)dlclose(mod.handle); 516113595Snectar mod.handle = NULL; 517113595Snectar nss_log(LOG_ERR, "%s, registration failed", mod.name); 518113595Snectar goto fin; 519113595Snectar } 520113595Snectar if (mod.mtabsize > 1) 521113595Snectar qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]), 522113595Snectar mtab_compare); 523113595Snectarfin: 524127012Sdes _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); 525113595Snectar vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); 526113595Snectar} 52765532Snectar 528113595Snectar 529113595Snectar 530113595Snectarstatic void 531113595Snectarns_mod_free(ns_mod *mod) 532113595Snectar{ 533113595Snectar 534113595Snectar free(mod->name); 535113595Snectar if (mod->handle == NULL) 536113595Snectar return; 537113595Snectar if (mod->unregister != NULL) 538113595Snectar mod->unregister(mod->mtab, mod->mtabsize); 539113595Snectar if (mod->handle != nss_builtin_handle) 540113595Snectar (void)dlclose(mod->handle); 541113595Snectar} 542113595Snectar 543113595Snectar 544113595Snectar 545113595Snectar/* 546113595Snectar * Cleanup 547113595Snectar */ 548113595Snectarstatic void 549113595Snectarnss_atexit(void) 550113595Snectar{ 551127625Snectar int isthreaded; 552127625Snectar 553127625Snectar isthreaded = __isthreaded; 554127625Snectar if (isthreaded) 555127625Snectar (void)_pthread_rwlock_wrlock(&nss_lock); 556127012Sdes VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 557113595Snectar (vector_free_elem)ns_dbt_free); 558127012Sdes VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 559113595Snectar (vector_free_elem)ns_mod_free); 560127625Snectar if (isthreaded) 561127625Snectar (void)_pthread_rwlock_unlock(&nss_lock); 562113595Snectar} 563113595Snectar 564113595Snectar 565113595Snectar 566113595Snectar/* 567113595Snectar * Finally, the actual implementation. 568113595Snectar */ 569113595Snectarstatic nss_method 570113595Snectarnss_method_lookup(const char *source, const char *database, 571113595Snectar const char *method, const ns_dtab disp_tab[], void **mdata) 572113595Snectar{ 573113595Snectar ns_mod *mod; 574113595Snectar ns_mtab *match, key; 575113595Snectar int i; 576113595Snectar 577113595Snectar if (disp_tab != NULL) 578113595Snectar for (i = 0; disp_tab[i].src != NULL; i++) 579113595Snectar if (strcasecmp(source, disp_tab[i].src) == 0) { 580113595Snectar *mdata = disp_tab[i].mdata; 581113595Snectar return (disp_tab[i].method); 582113595Snectar } 583113595Snectar mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod), 584113595Snectar string_compare); 585113595Snectar if (mod != NULL && mod->handle != NULL) { 586113595Snectar key.database = database; 587113595Snectar key.name = method; 588113595Snectar match = bsearch(&key, mod->mtab, mod->mtabsize, 589113595Snectar sizeof(mod->mtab[0]), mtab_compare); 590113595Snectar if (match != NULL) { 591113595Snectar *mdata = match->mdata; 592113595Snectar return (match->method); 593113595Snectar } 59465532Snectar } 595174716Sbushman 596113595Snectar *mdata = NULL; 597113595Snectar return (NULL); 59865532Snectar} 59965532Snectar 600192911Szmlstatic void 601192911Szmlfb_endstate(void *p) 602192911Szml{ 603192911Szml free(p); 604192911Szml} 60565532Snectar 606113595Snectar__weak_reference(_nsdispatch, nsdispatch); 607113595Snectar 60865532Snectarint 609113595Snectar_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, 610113595Snectar const char *method_name, const ns_src defaults[], ...) 61165532Snectar{ 61265532Snectar va_list ap; 61365532Snectar const ns_dbt *dbt; 61465532Snectar const ns_src *srclist; 615174547Sbushman nss_method method, fb_method; 616113595Snectar void *mdata; 617127625Snectar int isthreaded, serrno, i, result, srclistsize; 618192911Szml struct fb_state *st; 61965532Snectar 620158115Sume#ifdef NS_CACHING 621158115Sume nss_cache_data cache_data; 622158115Sume nss_cache_data *cache_data_p; 623158115Sume int cache_flag; 624158115Sume#endif 625174547Sbushman 626174547Sbushman dbt = NULL; 627174547Sbushman fb_method = NULL; 628158115Sume 629127625Snectar isthreaded = __isthreaded; 630113595Snectar serrno = errno; 631127625Snectar if (isthreaded) { 632127625Snectar result = _pthread_rwlock_rdlock(&nss_lock); 633127625Snectar if (result != 0) { 634127625Snectar result = NS_UNAVAIL; 635127625Snectar goto fin; 636127625Snectar } 637113595Snectar } 638192911Szml 639192911Szml result = fb_getstate(&st); 640192911Szml if (result != 0) { 641192911Szml result = NS_UNAVAIL; 642192911Szml goto fin; 643192911Szml } 644192911Szml 645113595Snectar result = nss_configure(); 646113595Snectar if (result != 0) { 647113595Snectar result = NS_UNAVAIL; 648113595Snectar goto fin; 649113595Snectar } 650192911Szml if (st->fb_dispatch == 0) { 651174547Sbushman dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap), 652174547Sbushman string_compare); 653174547Sbushman fb_method = nss_method_lookup(NSSRC_FALLBACK, database, 654174547Sbushman method_name, disp_tab, &mdata); 655174547Sbushman } 656174547Sbushman 65765532Snectar if (dbt != NULL) { 65865532Snectar srclist = dbt->srclist; 65965532Snectar srclistsize = dbt->srclistsize; 66065532Snectar } else { 66165532Snectar srclist = defaults; 66265532Snectar srclistsize = 0; 66365532Snectar while (srclist[srclistsize].name != NULL) 66465532Snectar srclistsize++; 66565532Snectar } 666158115Sume 667158115Sume#ifdef NS_CACHING 668158115Sume cache_data_p = NULL; 669158115Sume cache_flag = 0; 670158115Sume#endif 67165532Snectar for (i = 0; i < srclistsize; i++) { 672113595Snectar result = NS_NOTFOUND; 673113595Snectar method = nss_method_lookup(srclist[i].name, database, 674113595Snectar method_name, disp_tab, &mdata); 675158115Sume 676113595Snectar if (method != NULL) { 677158115Sume#ifdef NS_CACHING 678158115Sume if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 && 679158115Sume nss_cache_cycle_prevention_func == NULL) { 680158115Sume#ifdef NS_STRICT_LIBC_EID_CHECKING 681158115Sume if (issetugid() != 0) 682158115Sume continue; 683158115Sume#endif 684158115Sume cache_flag = 1; 685158115Sume 686158115Sume memset(&cache_data, 0, sizeof(nss_cache_data)); 687158115Sume cache_data.info = (nss_cache_info const *)mdata; 688158115Sume cache_data_p = &cache_data; 689158115Sume 690158115Sume va_start(ap, defaults); 691158115Sume if (cache_data.info->id_func != NULL) 692158115Sume result = __nss_common_cache_read(retval, 693158115Sume cache_data_p, ap); 694158115Sume else if (cache_data.info->marshal_func != NULL) 695158115Sume result = __nss_mp_cache_read(retval, 696158115Sume cache_data_p, ap); 697158115Sume else 698158115Sume result = __nss_mp_cache_end(retval, 699158115Sume cache_data_p, ap); 700158115Sume va_end(ap); 701158115Sume } else { 702158115Sume cache_flag = 0; 703213403Sume errno = 0; 704158115Sume va_start(ap, defaults); 705158115Sume result = method(retval, mdata, ap); 706158115Sume va_end(ap); 707158115Sume } 708158115Sume#else /* NS_CACHING */ 709213403Sume errno = 0; 71065532Snectar va_start(ap, defaults); 711113595Snectar result = method(retval, mdata, ap); 71265532Snectar va_end(ap); 713158115Sume#endif /* NS_CACHING */ 714158115Sume 715113595Snectar if (result & (srclist[i].flags)) 71665532Snectar break; 717174716Sbushman } else { 718174716Sbushman if (fb_method != NULL) { 719192911Szml st->fb_dispatch = 1; 720174716Sbushman va_start(ap, defaults); 721174716Sbushman result = fb_method(retval, 722174716Sbushman (void *)srclist[i].name, ap); 723174716Sbushman va_end(ap); 724192911Szml st->fb_dispatch = 0; 725174716Sbushman } else 726174716Sbushman nss_log(LOG_DEBUG, "%s, %s, %s, not found, " 727174716Sbushman "and no fallback provided", 728174716Sbushman srclist[i].name, database, method_name); 72965532Snectar } 73065532Snectar } 731158115Sume 732158115Sume#ifdef NS_CACHING 733158115Sume if (cache_data_p != NULL && 734158115Sume (result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) { 735158115Sume va_start(ap, defaults); 736158115Sume if (result == NS_SUCCESS) { 737158115Sume if (cache_data.info->id_func != NULL) 738158115Sume __nss_common_cache_write(retval, cache_data_p, 739158115Sume ap); 740158115Sume else if (cache_data.info->marshal_func != NULL) 741158115Sume __nss_mp_cache_write(retval, cache_data_p, ap); 742158115Sume } else if (result == NS_NOTFOUND) { 743158115Sume if (cache_data.info->id_func == NULL) { 744158115Sume if (cache_data.info->marshal_func != NULL) 745158115Sume __nss_mp_cache_write_submit(retval, 746158115Sume cache_data_p, ap); 747158115Sume } else 748158115Sume __nss_common_cache_write_negative(cache_data_p); 749158115Sume } 750158115Sume va_end(ap); 751158115Sume } 752158115Sume#endif /* NS_CACHING */ 753158115Sume 754127625Snectar if (isthreaded) 755127625Snectar (void)_pthread_rwlock_unlock(&nss_lock); 756113595Snectarfin: 757113595Snectar errno = serrno; 758113595Snectar return (result); 75965532Snectar} 760