1248aee62SJacques Vidrine /* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */ 2248aee62SJacques Vidrine 3248aee62SJacques Vidrine /*- 4248aee62SJacques Vidrine * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc. 5248aee62SJacques Vidrine * All rights reserved. 6248aee62SJacques Vidrine * 7248aee62SJacques Vidrine * This code is derived from software contributed to The NetBSD Foundation 8248aee62SJacques Vidrine * by Luke Mewburn. 9248aee62SJacques Vidrine * 10248aee62SJacques Vidrine * Redistribution and use in source and binary forms, with or without 11248aee62SJacques Vidrine * modification, are permitted provided that the following conditions 12248aee62SJacques Vidrine * are met: 13248aee62SJacques Vidrine * 1. Redistributions of source code must retain the above copyright 14248aee62SJacques Vidrine * notice, this list of conditions and the following disclaimer. 15248aee62SJacques Vidrine * 2. Redistributions in binary form must reproduce the above copyright 16248aee62SJacques Vidrine * notice, this list of conditions and the following disclaimer in the 17248aee62SJacques Vidrine * documentation and/or other materials provided with the distribution. 18248aee62SJacques Vidrine * 3. All advertising materials mentioning features or use of this software 19248aee62SJacques Vidrine * must display the following acknowledgement: 20248aee62SJacques Vidrine * This product includes software developed by the NetBSD 21248aee62SJacques Vidrine * Foundation, Inc. and its contributors. 22248aee62SJacques Vidrine * 4. Neither the name of The NetBSD Foundation nor the names of its 23248aee62SJacques Vidrine * contributors may be used to endorse or promote products derived 24248aee62SJacques Vidrine * from this software without specific prior written permission. 25248aee62SJacques Vidrine * 26248aee62SJacques Vidrine * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27248aee62SJacques Vidrine * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28248aee62SJacques Vidrine * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29248aee62SJacques Vidrine * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30248aee62SJacques Vidrine * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31248aee62SJacques Vidrine * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32248aee62SJacques Vidrine * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33248aee62SJacques Vidrine * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34248aee62SJacques Vidrine * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35248aee62SJacques Vidrine * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36248aee62SJacques Vidrine * POSSIBILITY OF SUCH DAMAGE. 37248aee62SJacques Vidrine */ 3846d93063SJacques Vidrine /*- 3946d93063SJacques Vidrine * Copyright (c) 2003 Networks Associates Technology, Inc. 4046d93063SJacques Vidrine * All rights reserved. 4146d93063SJacques Vidrine * 4246d93063SJacques Vidrine * Portions of this software were developed for the FreeBSD Project by 4346d93063SJacques Vidrine * Jacques A. Vidrine, Safeport Network Services, and Network 4446d93063SJacques Vidrine * Associates Laboratories, the Security Research Division of Network 4546d93063SJacques Vidrine * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 4646d93063SJacques Vidrine * ("CBOSS"), as part of the DARPA CHATS research program. 4746d93063SJacques Vidrine * 4846d93063SJacques Vidrine * Redistribution and use in source and binary forms, with or without 4946d93063SJacques Vidrine * modification, are permitted provided that the following conditions 5046d93063SJacques Vidrine * are met: 5146d93063SJacques Vidrine * 1. Redistributions of source code must retain the above copyright 5246d93063SJacques Vidrine * notice, this list of conditions and the following disclaimer. 5346d93063SJacques Vidrine * 2. Redistributions in binary form must reproduce the above copyright 5446d93063SJacques Vidrine * notice, this list of conditions and the following disclaimer in the 5546d93063SJacques Vidrine * documentation and/or other materials provided with the distribution. 5646d93063SJacques Vidrine * 5746d93063SJacques Vidrine * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 5846d93063SJacques Vidrine * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5946d93063SJacques Vidrine * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 6046d93063SJacques Vidrine * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 6146d93063SJacques Vidrine * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6246d93063SJacques Vidrine * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6346d93063SJacques Vidrine * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6446d93063SJacques Vidrine * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6546d93063SJacques Vidrine * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6646d93063SJacques Vidrine * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6746d93063SJacques Vidrine * SUCH DAMAGE. 6846d93063SJacques Vidrine * 6946d93063SJacques Vidrine */ 70248aee62SJacques Vidrine #include <sys/cdefs.h> 71333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 72248aee62SJacques Vidrine 7346d93063SJacques Vidrine #include "namespace.h" 74248aee62SJacques Vidrine #include <sys/param.h> 75248aee62SJacques Vidrine #include <sys/stat.h> 76248aee62SJacques Vidrine 7746d93063SJacques Vidrine #include <dlfcn.h> 7846d93063SJacques Vidrine #include <errno.h> 79248aee62SJacques Vidrine #include <fcntl.h> 80248aee62SJacques Vidrine #define _NS_PRIVATE 81248aee62SJacques Vidrine #include <nsswitch.h> 8246d93063SJacques Vidrine #include <pthread.h> 83248aee62SJacques Vidrine #include <stdio.h> 84248aee62SJacques Vidrine #include <stdlib.h> 85248aee62SJacques Vidrine #include <string.h> 8646d93063SJacques Vidrine #include <syslog.h> 87248aee62SJacques Vidrine #include <unistd.h> 882bbd7cf8SJacques Vidrine #include "un-namespace.h" 89248aee62SJacques Vidrine 9046d93063SJacques Vidrine enum _nss_constants { 9146d93063SJacques Vidrine /* Number of elements allocated when we grow a vector */ 9246d93063SJacques Vidrine ELEMSPERCHUNK = 8 9346d93063SJacques Vidrine }; 9446d93063SJacques Vidrine 9546d93063SJacques Vidrine /* 9646d93063SJacques Vidrine * Global NSS data structures are mostly read-only, but we update 9746d93063SJacques Vidrine * them when we read or re-read the nsswitch.conf. 9846d93063SJacques Vidrine */ 9946d93063SJacques Vidrine static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; 10046d93063SJacques Vidrine 10146d93063SJacques Vidrine /* 10246d93063SJacques Vidrine * Runtime determination of whether we are dynamically linked or not. 10346d93063SJacques Vidrine */ 10446d93063SJacques Vidrine extern int _DYNAMIC __attribute__ ((weak)); 10546d93063SJacques Vidrine #define is_dynamic() (&_DYNAMIC != NULL) 10646d93063SJacques Vidrine 107248aee62SJacques Vidrine /* 108248aee62SJacques Vidrine * default sourcelist: `files' 109248aee62SJacques Vidrine */ 110248aee62SJacques Vidrine const ns_src __nsdefaultsrc[] = { 111248aee62SJacques Vidrine { NSSRC_FILES, NS_SUCCESS }, 112248aee62SJacques Vidrine { 0 }, 113248aee62SJacques Vidrine }; 114248aee62SJacques Vidrine 11546d93063SJacques Vidrine /* Database, source mappings. */ 11646d93063SJacques Vidrine static unsigned int _nsmapsize; 117248aee62SJacques Vidrine static ns_dbt *_nsmap = NULL; 118248aee62SJacques Vidrine 11946d93063SJacques Vidrine /* NSS modules. */ 12046d93063SJacques Vidrine static unsigned int _nsmodsize; 12146d93063SJacques Vidrine static ns_mod *_nsmod; 12246d93063SJacques Vidrine 12346d93063SJacques Vidrine /* Placeholder for builtin modules' dlopen `handle'. */ 12446d93063SJacques Vidrine static int __nss_builtin_handle; 12546d93063SJacques Vidrine static void *nss_builtin_handle = &__nss_builtin_handle; 12646d93063SJacques Vidrine 127248aee62SJacques Vidrine /* 12846d93063SJacques Vidrine * Attempt to spew relatively uniform messages to syslog. 129248aee62SJacques Vidrine */ 13046d93063SJacques Vidrine #define nss_log(level, fmt, ...) \ 13146d93063SJacques Vidrine syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__) 13246d93063SJacques Vidrine #define nss_log_simple(level, s) \ 13346d93063SJacques Vidrine syslog((level), "NSSWITCH(%s): " s, __func__) 13446d93063SJacques Vidrine 13546d93063SJacques Vidrine /* 13646d93063SJacques Vidrine * Dynamically growable arrays are used for lists of databases, sources, 13746d93063SJacques Vidrine * and modules. The following `vector' interface is used to isolate the 13846d93063SJacques Vidrine * common operations. 13946d93063SJacques Vidrine */ 14046d93063SJacques Vidrine typedef int (*vector_comparison)(const void *, const void *); 14146d93063SJacques Vidrine typedef void (*vector_free_elem)(void *); 14246d93063SJacques Vidrine static void vector_sort(void *, unsigned int, size_t, 14346d93063SJacques Vidrine vector_comparison); 1444705e3daSDag-Erling Smørgrav static void vector_free(void *, unsigned int *, size_t, 14546d93063SJacques Vidrine vector_free_elem); 14646d93063SJacques Vidrine static void *vector_ref(unsigned int, void *, unsigned int, size_t); 14746d93063SJacques Vidrine static void *vector_search(const void *, void *, unsigned int, size_t, 14846d93063SJacques Vidrine vector_comparison); 1494705e3daSDag-Erling Smørgrav static void *vector_append(const void *, void *, unsigned int *, size_t); 150248aee62SJacques Vidrine 151248aee62SJacques Vidrine 15246d93063SJacques Vidrine /* 15346d93063SJacques Vidrine * Internal interfaces. 15446d93063SJacques Vidrine */ 15546d93063SJacques Vidrine static int string_compare(const void *, const void *); 15646d93063SJacques Vidrine static int mtab_compare(const void *, const void *); 15746d93063SJacques Vidrine static int nss_configure(void); 15846d93063SJacques Vidrine static void ns_dbt_free(ns_dbt *); 15946d93063SJacques Vidrine static void ns_mod_free(ns_mod *); 16046d93063SJacques Vidrine static void ns_src_free(ns_src **, int); 16146d93063SJacques Vidrine static void nss_load_builtin_modules(void); 16246d93063SJacques Vidrine static void nss_load_module(const char *, nss_module_register_fn); 16346d93063SJacques Vidrine static void nss_atexit(void); 16446d93063SJacques Vidrine /* nsparser */ 16546d93063SJacques Vidrine extern FILE *_nsyyin; 166248aee62SJacques Vidrine 167248aee62SJacques Vidrine 16846d93063SJacques Vidrine /* 16946d93063SJacques Vidrine * The vector operations 17046d93063SJacques Vidrine */ 17146d93063SJacques Vidrine static void 17246d93063SJacques Vidrine vector_sort(void *vec, unsigned int count, size_t esize, 17346d93063SJacques Vidrine vector_comparison comparison) 174248aee62SJacques Vidrine { 17546d93063SJacques Vidrine qsort(vec, count, esize, comparison); 176248aee62SJacques Vidrine } 177248aee62SJacques Vidrine 178248aee62SJacques Vidrine 17946d93063SJacques Vidrine static void * 18046d93063SJacques Vidrine vector_search(const void *key, void *vec, unsigned int count, size_t esize, 18146d93063SJacques Vidrine vector_comparison comparison) 182248aee62SJacques Vidrine { 18346d93063SJacques Vidrine return (bsearch(key, vec, count, esize, comparison)); 184248aee62SJacques Vidrine } 185248aee62SJacques Vidrine 186248aee62SJacques Vidrine 1874705e3daSDag-Erling Smørgrav static void * 1884705e3daSDag-Erling Smørgrav vector_append(const void *elem, void *vec, unsigned int *count, size_t esize) 18946d93063SJacques Vidrine { 19046d93063SJacques Vidrine void *p; 19146d93063SJacques Vidrine 19246d93063SJacques Vidrine if ((*count % ELEMSPERCHUNK) == 0) { 1934705e3daSDag-Erling Smørgrav p = realloc(vec, (*count + ELEMSPERCHUNK) * esize); 19446d93063SJacques Vidrine if (p == NULL) { 19546d93063SJacques Vidrine nss_log_simple(LOG_ERR, "memory allocation failure"); 1964705e3daSDag-Erling Smørgrav return (vec); 19746d93063SJacques Vidrine } 1984705e3daSDag-Erling Smørgrav vec = p; 1994705e3daSDag-Erling Smørgrav } 2004705e3daSDag-Erling Smørgrav memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize); 20146d93063SJacques Vidrine (*count)++; 2024705e3daSDag-Erling Smørgrav return (vec); 20346d93063SJacques Vidrine } 20446d93063SJacques Vidrine 20546d93063SJacques Vidrine 20646d93063SJacques Vidrine static void * 20746d93063SJacques Vidrine vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize) 20846d93063SJacques Vidrine { 20946d93063SJacques Vidrine if (i < count) 21046d93063SJacques Vidrine return (void *)((uintptr_t)vec + (i * esize)); 21146d93063SJacques Vidrine else 21246d93063SJacques Vidrine return (NULL); 21346d93063SJacques Vidrine } 21446d93063SJacques Vidrine 21546d93063SJacques Vidrine 2164705e3daSDag-Erling Smørgrav #define VECTOR_FREE(v, c, s, f) \ 2174705e3daSDag-Erling Smørgrav do { vector_free(v, c, s, f); v = NULL; } while (0) 21846d93063SJacques Vidrine static void 2194705e3daSDag-Erling Smørgrav vector_free(void *vec, unsigned int *count, size_t esize, 22046d93063SJacques Vidrine vector_free_elem free_elem) 22146d93063SJacques Vidrine { 22246d93063SJacques Vidrine unsigned int i; 22346d93063SJacques Vidrine void *elem; 22446d93063SJacques Vidrine 22546d93063SJacques Vidrine for (i = 0; i < *count; i++) { 2264705e3daSDag-Erling Smørgrav elem = vector_ref(i, vec, *count, esize); 22746d93063SJacques Vidrine if (elem != NULL) 22846d93063SJacques Vidrine free_elem(elem); 22946d93063SJacques Vidrine } 2304705e3daSDag-Erling Smørgrav free(vec); 23146d93063SJacques Vidrine *count = 0; 23246d93063SJacques Vidrine } 23346d93063SJacques Vidrine 23446d93063SJacques Vidrine 23546d93063SJacques Vidrine 23646d93063SJacques Vidrine /* 23746d93063SJacques Vidrine * Comparison functions for vector_search. 23846d93063SJacques Vidrine */ 23946d93063SJacques Vidrine static int 24046d93063SJacques Vidrine string_compare(const void *a, const void *b) 24146d93063SJacques Vidrine { 24246d93063SJacques Vidrine return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); 24346d93063SJacques Vidrine } 24446d93063SJacques Vidrine 24546d93063SJacques Vidrine 24646d93063SJacques Vidrine static int 24746d93063SJacques Vidrine mtab_compare(const void *a, const void *b) 24846d93063SJacques Vidrine { 24946d93063SJacques Vidrine int cmp; 25046d93063SJacques Vidrine 25146d93063SJacques Vidrine cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name); 25246d93063SJacques Vidrine if (cmp != 0) 25346d93063SJacques Vidrine return (cmp); 25446d93063SJacques Vidrine else 25546d93063SJacques Vidrine return (strcmp(((const ns_mtab *)a)->database, 25646d93063SJacques Vidrine ((const ns_mtab *)b)->database)); 25746d93063SJacques Vidrine } 25846d93063SJacques Vidrine 25946d93063SJacques Vidrine 26046d93063SJacques Vidrine 26146d93063SJacques Vidrine /* 26246d93063SJacques Vidrine * NSS nsmap management. 26346d93063SJacques Vidrine */ 264248aee62SJacques Vidrine void 26546d93063SJacques Vidrine _nsdbtaddsrc(ns_dbt *dbt, const ns_src *src) 26646d93063SJacques Vidrine { 26746d93063SJacques Vidrine const ns_mod *modp; 26846d93063SJacques Vidrine 2694705e3daSDag-Erling Smørgrav dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize, 27046d93063SJacques Vidrine sizeof(*src)); 27146d93063SJacques Vidrine modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod), 27246d93063SJacques Vidrine string_compare); 27346d93063SJacques Vidrine if (modp == NULL) 27446d93063SJacques Vidrine nss_load_module(src->name, NULL); 27546d93063SJacques Vidrine } 27646d93063SJacques Vidrine 27746d93063SJacques Vidrine 27846d93063SJacques Vidrine #ifdef _NSS_DEBUG 27946d93063SJacques Vidrine void 28046d93063SJacques Vidrine _nsdbtdump(const ns_dbt *dbt) 281248aee62SJacques Vidrine { 282248aee62SJacques Vidrine int i; 283248aee62SJacques Vidrine 284248aee62SJacques Vidrine printf("%s (%d source%s):", dbt->name, dbt->srclistsize, 285248aee62SJacques Vidrine dbt->srclistsize == 1 ? "" : "s"); 28646d93063SJacques Vidrine for (i = 0; i < (int)dbt->srclistsize; i++) { 287248aee62SJacques Vidrine printf(" %s", dbt->srclist[i].name); 288248aee62SJacques Vidrine if (!(dbt->srclist[i].flags & 289248aee62SJacques Vidrine (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) && 290248aee62SJacques Vidrine (dbt->srclist[i].flags & NS_SUCCESS)) 291248aee62SJacques Vidrine continue; 292248aee62SJacques Vidrine printf(" ["); 293248aee62SJacques Vidrine if (!(dbt->srclist[i].flags & NS_SUCCESS)) 294248aee62SJacques Vidrine printf(" SUCCESS=continue"); 295248aee62SJacques Vidrine if (dbt->srclist[i].flags & NS_UNAVAIL) 296248aee62SJacques Vidrine printf(" UNAVAIL=return"); 297248aee62SJacques Vidrine if (dbt->srclist[i].flags & NS_NOTFOUND) 298248aee62SJacques Vidrine printf(" NOTFOUND=return"); 299248aee62SJacques Vidrine if (dbt->srclist[i].flags & NS_TRYAGAIN) 300248aee62SJacques Vidrine printf(" TRYAGAIN=return"); 301248aee62SJacques Vidrine printf(" ]"); 302248aee62SJacques Vidrine } 303248aee62SJacques Vidrine printf("\n"); 304248aee62SJacques Vidrine } 30546d93063SJacques Vidrine #endif 306248aee62SJacques Vidrine 307248aee62SJacques Vidrine 30846d93063SJacques Vidrine /* 30946d93063SJacques Vidrine * The first time nsdispatch is called (during a process's lifetime, 31046d93063SJacques Vidrine * or after nsswitch.conf has been updated), nss_configure will 31146d93063SJacques Vidrine * prepare global data needed by NSS. 31246d93063SJacques Vidrine */ 31346d93063SJacques Vidrine static int 31446d93063SJacques Vidrine nss_configure(void) 315248aee62SJacques Vidrine { 31646d93063SJacques Vidrine static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER; 317248aee62SJacques Vidrine static time_t confmod; 318248aee62SJacques Vidrine struct stat statbuf; 319a03fd3b6SJacques Vidrine int result, isthreaded; 32046d93063SJacques Vidrine const char *path; 321248aee62SJacques Vidrine 322a03fd3b6SJacques Vidrine result = 0; 323a03fd3b6SJacques Vidrine isthreaded = __isthreaded; 32446d93063SJacques Vidrine #if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT) 32546d93063SJacques Vidrine /* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built 32646d93063SJacques Vidrine * for debugging purposes and MUST NEVER be used in production. 32746d93063SJacques Vidrine */ 32846d93063SJacques Vidrine path = getenv("NSSWITCH_CONF"); 32946d93063SJacques Vidrine if (path == NULL) 33046d93063SJacques Vidrine #endif 33146d93063SJacques Vidrine path = _PATH_NS_CONF; 33246d93063SJacques Vidrine if (stat(path, &statbuf) != 0) 33346d93063SJacques Vidrine return (0); 33446d93063SJacques Vidrine if (statbuf.st_mtime <= confmod) 33546d93063SJacques Vidrine return (0); 336a03fd3b6SJacques Vidrine if (isthreaded) { 33746d93063SJacques Vidrine result = _pthread_mutex_trylock(&conf_lock); 33846d93063SJacques Vidrine if (result != 0) 33946d93063SJacques Vidrine return (0); 34046d93063SJacques Vidrine (void)_pthread_rwlock_unlock(&nss_lock); 34146d93063SJacques Vidrine result = _pthread_rwlock_wrlock(&nss_lock); 34246d93063SJacques Vidrine if (result != 0) 34346d93063SJacques Vidrine goto fin2; 344a03fd3b6SJacques Vidrine } 34546d93063SJacques Vidrine _nsyyin = fopen(path, "r"); 3468074e24dSJacques Vidrine if (_nsyyin == NULL) 34746d93063SJacques Vidrine goto fin; 3484705e3daSDag-Erling Smørgrav VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 34946d93063SJacques Vidrine (vector_free_elem)ns_dbt_free); 3504705e3daSDag-Erling Smørgrav VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 35146d93063SJacques Vidrine (vector_free_elem)ns_mod_free); 35246d93063SJacques Vidrine nss_load_builtin_modules(); 353248aee62SJacques Vidrine _nsyyparse(); 354248aee62SJacques Vidrine (void)fclose(_nsyyin); 35546d93063SJacques Vidrine vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare); 35646d93063SJacques Vidrine if (confmod == 0) 35746d93063SJacques Vidrine (void)atexit(nss_atexit); 358248aee62SJacques Vidrine confmod = statbuf.st_mtime; 35946d93063SJacques Vidrine fin: 360a03fd3b6SJacques Vidrine if (isthreaded) { 36146d93063SJacques Vidrine (void)_pthread_rwlock_unlock(&nss_lock); 362a03fd3b6SJacques Vidrine if (result == 0) 36346d93063SJacques Vidrine result = _pthread_rwlock_rdlock(&nss_lock); 364a03fd3b6SJacques Vidrine } 36546d93063SJacques Vidrine fin2: 366a03fd3b6SJacques Vidrine if (isthreaded) 36746d93063SJacques Vidrine (void)_pthread_mutex_unlock(&conf_lock); 36846d93063SJacques Vidrine return (result); 369248aee62SJacques Vidrine } 370248aee62SJacques Vidrine 371248aee62SJacques Vidrine 372248aee62SJacques Vidrine void 37346d93063SJacques Vidrine _nsdbtput(const ns_dbt *dbt) 374248aee62SJacques Vidrine { 37546d93063SJacques Vidrine unsigned int i; 37646d93063SJacques Vidrine ns_dbt *p; 377248aee62SJacques Vidrine 378248aee62SJacques Vidrine for (i = 0; i < _nsmapsize; i++) { 37946d93063SJacques Vidrine p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap)); 38046d93063SJacques Vidrine if (string_compare(&dbt->name, &p->name) == 0) { 381248aee62SJacques Vidrine /* overwrite existing entry */ 38246d93063SJacques Vidrine if (p->srclist != NULL) 38346d93063SJacques Vidrine ns_src_free(&p->srclist, p->srclistsize); 38446d93063SJacques Vidrine memmove(p, dbt, sizeof(*dbt)); 385248aee62SJacques Vidrine return; 386248aee62SJacques Vidrine } 387248aee62SJacques Vidrine } 3884705e3daSDag-Erling Smørgrav _nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap)); 389248aee62SJacques Vidrine } 390248aee62SJacques Vidrine 391248aee62SJacques Vidrine 39246d93063SJacques Vidrine static void 39346d93063SJacques Vidrine ns_dbt_free(ns_dbt *dbt) 39446d93063SJacques Vidrine { 39546d93063SJacques Vidrine ns_src_free(&dbt->srclist, dbt->srclistsize); 39646d93063SJacques Vidrine } 39746d93063SJacques Vidrine 39846d93063SJacques Vidrine 39946d93063SJacques Vidrine static void 40046d93063SJacques Vidrine ns_src_free(ns_src **src, int srclistsize) 40146d93063SJacques Vidrine { 40246d93063SJacques Vidrine int i; 40346d93063SJacques Vidrine 40446d93063SJacques Vidrine for (i = 0; i < srclistsize; i++) 40546d93063SJacques Vidrine if ((*src)[i].name != NULL) 40646d93063SJacques Vidrine /* This one was allocated by nslexer. You'll just 40746d93063SJacques Vidrine * have to trust me. 40846d93063SJacques Vidrine */ 40946d93063SJacques Vidrine free((void *)((*src)[i].name)); 41046d93063SJacques Vidrine free(*src); 41146d93063SJacques Vidrine *src = NULL; 41246d93063SJacques Vidrine } 41346d93063SJacques Vidrine 41446d93063SJacques Vidrine 41546d93063SJacques Vidrine 41646d93063SJacques Vidrine /* 41746d93063SJacques Vidrine * NSS module management. 41846d93063SJacques Vidrine */ 41946d93063SJacques Vidrine /* The built-in NSS modules are all loaded at once. */ 42046d93063SJacques Vidrine #define NSS_BACKEND(name, reg) \ 42146d93063SJacques Vidrine ns_mtab *reg(unsigned int *, nss_module_unregister_fn *); 42246d93063SJacques Vidrine #include "nss_backends.h" 42346d93063SJacques Vidrine #undef NSS_BACKEND 42446d93063SJacques Vidrine 42546d93063SJacques Vidrine static void 42646d93063SJacques Vidrine nss_load_builtin_modules(void) 42746d93063SJacques Vidrine { 42846d93063SJacques Vidrine #define NSS_BACKEND(name, reg) nss_load_module(#name, reg); 42946d93063SJacques Vidrine #include "nss_backends.h" 43046d93063SJacques Vidrine #undef NSS_BACKEND 43146d93063SJacques Vidrine } 43246d93063SJacques Vidrine 43346d93063SJacques Vidrine 43446d93063SJacques Vidrine /* Load a built-in or dynamically linked module. If the `reg_fn' 43546d93063SJacques Vidrine * argument is non-NULL, assume a built-in module and use reg_fn to 43646d93063SJacques Vidrine * register it. Otherwise, search for a dynamic NSS module. 43746d93063SJacques Vidrine */ 43846d93063SJacques Vidrine static void 43946d93063SJacques Vidrine nss_load_module(const char *source, nss_module_register_fn reg_fn) 44046d93063SJacques Vidrine { 44146d93063SJacques Vidrine char buf[PATH_MAX]; 44246d93063SJacques Vidrine ns_mod mod; 44346d93063SJacques Vidrine nss_module_register_fn fn; 44446d93063SJacques Vidrine 44546d93063SJacques Vidrine memset(&mod, 0, sizeof(mod)); 44646d93063SJacques Vidrine mod.name = strdup(source); 44746d93063SJacques Vidrine if (mod.name == NULL) { 44846d93063SJacques Vidrine nss_log_simple(LOG_ERR, "memory allocation failure"); 44946d93063SJacques Vidrine return; 45046d93063SJacques Vidrine } 45146d93063SJacques Vidrine if (reg_fn != NULL) { 45246d93063SJacques Vidrine /* The placeholder is required, as a NULL handle 45346d93063SJacques Vidrine * represents an invalid module. 45446d93063SJacques Vidrine */ 45546d93063SJacques Vidrine mod.handle = nss_builtin_handle; 45646d93063SJacques Vidrine fn = reg_fn; 45746d93063SJacques Vidrine } else if (!is_dynamic()) 45846d93063SJacques Vidrine goto fin; 45946d93063SJacques Vidrine else { 46046d93063SJacques Vidrine if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name, 46146d93063SJacques Vidrine NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf)) 46246d93063SJacques Vidrine goto fin; 46346d93063SJacques Vidrine mod.handle = dlopen(buf, RTLD_LOCAL|RTLD_LAZY); 46446d93063SJacques Vidrine if (mod.handle == NULL) { 46546d93063SJacques Vidrine #ifdef _NSS_DEBUG 46646d93063SJacques Vidrine /* This gets pretty annoying since the built-in 46746d93063SJacques Vidrine * sources aren't modules yet. 46846d93063SJacques Vidrine */ 46946d93063SJacques Vidrine nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror()); 47046d93063SJacques Vidrine #endif 47146d93063SJacques Vidrine goto fin; 47246d93063SJacques Vidrine } 47346d93063SJacques Vidrine fn = (nss_module_register_fn)dlfunc(mod.handle, 47446d93063SJacques Vidrine "nss_module_register"); 47546d93063SJacques Vidrine if (fn == NULL) { 47646d93063SJacques Vidrine (void)dlclose(mod.handle); 47746d93063SJacques Vidrine mod.handle = NULL; 47846d93063SJacques Vidrine nss_log(LOG_ERR, "%s, %s", mod.name, dlerror()); 47946d93063SJacques Vidrine goto fin; 48046d93063SJacques Vidrine } 48146d93063SJacques Vidrine } 48246d93063SJacques Vidrine mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister); 48346d93063SJacques Vidrine if (mod.mtab == NULL || mod.mtabsize == 0) { 48446d93063SJacques Vidrine if (mod.handle != nss_builtin_handle) 48546d93063SJacques Vidrine (void)dlclose(mod.handle); 48646d93063SJacques Vidrine mod.handle = NULL; 48746d93063SJacques Vidrine nss_log(LOG_ERR, "%s, registration failed", mod.name); 48846d93063SJacques Vidrine goto fin; 48946d93063SJacques Vidrine } 49046d93063SJacques Vidrine if (mod.mtabsize > 1) 49146d93063SJacques Vidrine qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]), 49246d93063SJacques Vidrine mtab_compare); 49346d93063SJacques Vidrine fin: 4944705e3daSDag-Erling Smørgrav _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); 49546d93063SJacques Vidrine vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); 49646d93063SJacques Vidrine } 49746d93063SJacques Vidrine 49846d93063SJacques Vidrine 49946d93063SJacques Vidrine 50046d93063SJacques Vidrine static void 50146d93063SJacques Vidrine ns_mod_free(ns_mod *mod) 50246d93063SJacques Vidrine { 50346d93063SJacques Vidrine 50446d93063SJacques Vidrine free(mod->name); 50546d93063SJacques Vidrine if (mod->handle == NULL) 50646d93063SJacques Vidrine return; 50746d93063SJacques Vidrine if (mod->unregister != NULL) 50846d93063SJacques Vidrine mod->unregister(mod->mtab, mod->mtabsize); 50946d93063SJacques Vidrine if (mod->handle != nss_builtin_handle) 51046d93063SJacques Vidrine (void)dlclose(mod->handle); 51146d93063SJacques Vidrine } 51246d93063SJacques Vidrine 51346d93063SJacques Vidrine 51446d93063SJacques Vidrine 51546d93063SJacques Vidrine /* 51646d93063SJacques Vidrine * Cleanup 51746d93063SJacques Vidrine */ 51846d93063SJacques Vidrine static void 51946d93063SJacques Vidrine nss_atexit(void) 52046d93063SJacques Vidrine { 521a03fd3b6SJacques Vidrine int isthreaded; 522a03fd3b6SJacques Vidrine 523a03fd3b6SJacques Vidrine isthreaded = __isthreaded; 524a03fd3b6SJacques Vidrine if (isthreaded) 52546d93063SJacques Vidrine (void)_pthread_rwlock_wrlock(&nss_lock); 5264705e3daSDag-Erling Smørgrav VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 52746d93063SJacques Vidrine (vector_free_elem)ns_dbt_free); 5284705e3daSDag-Erling Smørgrav VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 52946d93063SJacques Vidrine (vector_free_elem)ns_mod_free); 530a03fd3b6SJacques Vidrine if (isthreaded) 53146d93063SJacques Vidrine (void)_pthread_rwlock_unlock(&nss_lock); 53246d93063SJacques Vidrine } 53346d93063SJacques Vidrine 53446d93063SJacques Vidrine 53546d93063SJacques Vidrine 53646d93063SJacques Vidrine /* 53746d93063SJacques Vidrine * Finally, the actual implementation. 53846d93063SJacques Vidrine */ 53946d93063SJacques Vidrine static nss_method 54046d93063SJacques Vidrine nss_method_lookup(const char *source, const char *database, 54146d93063SJacques Vidrine const char *method, const ns_dtab disp_tab[], void **mdata) 54246d93063SJacques Vidrine { 54346d93063SJacques Vidrine ns_mod *mod; 54446d93063SJacques Vidrine ns_mtab *match, key; 54546d93063SJacques Vidrine int i; 54646d93063SJacques Vidrine 54746d93063SJacques Vidrine if (disp_tab != NULL) 54846d93063SJacques Vidrine for (i = 0; disp_tab[i].src != NULL; i++) 54946d93063SJacques Vidrine if (strcasecmp(source, disp_tab[i].src) == 0) { 55046d93063SJacques Vidrine *mdata = disp_tab[i].mdata; 55146d93063SJacques Vidrine return (disp_tab[i].method); 55246d93063SJacques Vidrine } 55346d93063SJacques Vidrine mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod), 55446d93063SJacques Vidrine string_compare); 55546d93063SJacques Vidrine if (mod != NULL && mod->handle != NULL) { 55646d93063SJacques Vidrine key.database = database; 55746d93063SJacques Vidrine key.name = method; 55846d93063SJacques Vidrine match = bsearch(&key, mod->mtab, mod->mtabsize, 55946d93063SJacques Vidrine sizeof(mod->mtab[0]), mtab_compare); 56046d93063SJacques Vidrine if (match != NULL) { 56146d93063SJacques Vidrine *mdata = match->mdata; 56246d93063SJacques Vidrine return (match->method); 56346d93063SJacques Vidrine } 56446d93063SJacques Vidrine } 56543f9b252SJacques Vidrine if (is_dynamic()) 56643f9b252SJacques Vidrine nss_log(LOG_DEBUG, "%s, %s, %s, not found", source, database, 56743f9b252SJacques Vidrine method); 56846d93063SJacques Vidrine *mdata = NULL; 56946d93063SJacques Vidrine return (NULL); 57046d93063SJacques Vidrine } 57146d93063SJacques Vidrine 57246d93063SJacques Vidrine 57346d93063SJacques Vidrine __weak_reference(_nsdispatch, nsdispatch); 57446d93063SJacques Vidrine 575248aee62SJacques Vidrine int 57646d93063SJacques Vidrine _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, 57746d93063SJacques Vidrine const char *method_name, const ns_src defaults[], ...) 578248aee62SJacques Vidrine { 579248aee62SJacques Vidrine va_list ap; 580248aee62SJacques Vidrine const ns_dbt *dbt; 581248aee62SJacques Vidrine const ns_src *srclist; 58246d93063SJacques Vidrine nss_method method; 58346d93063SJacques Vidrine void *mdata; 584a03fd3b6SJacques Vidrine int isthreaded, serrno, i, result, srclistsize; 585248aee62SJacques Vidrine 586a03fd3b6SJacques Vidrine isthreaded = __isthreaded; 58746d93063SJacques Vidrine serrno = errno; 588a03fd3b6SJacques Vidrine if (isthreaded) { 58946d93063SJacques Vidrine result = _pthread_rwlock_rdlock(&nss_lock); 59046d93063SJacques Vidrine if (result != 0) { 59146d93063SJacques Vidrine result = NS_UNAVAIL; 59246d93063SJacques Vidrine goto fin; 59346d93063SJacques Vidrine } 594a03fd3b6SJacques Vidrine } 59546d93063SJacques Vidrine result = nss_configure(); 59646d93063SJacques Vidrine if (result != 0) { 59746d93063SJacques Vidrine result = NS_UNAVAIL; 59846d93063SJacques Vidrine goto fin; 59946d93063SJacques Vidrine } 60046d93063SJacques Vidrine dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap), 60146d93063SJacques Vidrine string_compare); 602248aee62SJacques Vidrine if (dbt != NULL) { 603248aee62SJacques Vidrine srclist = dbt->srclist; 604248aee62SJacques Vidrine srclistsize = dbt->srclistsize; 605248aee62SJacques Vidrine } else { 606248aee62SJacques Vidrine srclist = defaults; 607248aee62SJacques Vidrine srclistsize = 0; 608248aee62SJacques Vidrine while (srclist[srclistsize].name != NULL) 609248aee62SJacques Vidrine srclistsize++; 610248aee62SJacques Vidrine } 611248aee62SJacques Vidrine for (i = 0; i < srclistsize; i++) { 61246d93063SJacques Vidrine result = NS_NOTFOUND; 61346d93063SJacques Vidrine method = nss_method_lookup(srclist[i].name, database, 61446d93063SJacques Vidrine method_name, disp_tab, &mdata); 61546d93063SJacques Vidrine if (method != NULL) { 616248aee62SJacques Vidrine va_start(ap, defaults); 61746d93063SJacques Vidrine result = method(retval, mdata, ap); 618248aee62SJacques Vidrine va_end(ap); 61946d93063SJacques Vidrine if (result & (srclist[i].flags)) 620248aee62SJacques Vidrine break; 621248aee62SJacques Vidrine } 622248aee62SJacques Vidrine } 623a03fd3b6SJacques Vidrine if (isthreaded) 62446d93063SJacques Vidrine (void)_pthread_rwlock_unlock(&nss_lock); 62546d93063SJacques Vidrine fin: 62646d93063SJacques Vidrine errno = serrno; 62746d93063SJacques Vidrine return (result); 628248aee62SJacques Vidrine } 629