diff options
Diffstat (limited to 'lib/libc/net/nsdispatch.c')
-rw-r--r-- | lib/libc/net/nsdispatch.c | 766 |
1 files changed, 0 insertions, 766 deletions
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c deleted file mode 100644 index 6b7bd02..0000000 --- a/lib/libc/net/nsdispatch.c +++ /dev/null @@ -1,766 +0,0 @@ -/* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */ - -/*- - * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Luke Mewburn. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Copyright (c) 2003 Networks Associates Technology, Inc. - * All rights reserved. - * - * Portions of this software were developed for the FreeBSD Project by - * Jacques A. Vidrine, Safeport Network Services, and Network - * Associates Laboratories, the Security Research Division of Network - * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 - * ("CBOSS"), as part of the DARPA CHATS research program. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include "namespace.h" -#include <sys/param.h> -#include <sys/stat.h> - -#include <dlfcn.h> -#include <errno.h> -#include <fcntl.h> -#define _NS_PRIVATE -#include <nsswitch.h> -#include <pthread.h> -#include <pthread_np.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include "un-namespace.h" -#include "nss_tls.h" -#include "libc_private.h" -#ifdef NS_CACHING -#include "nscache.h" -#endif - -enum _nss_constants { - /* Number of elements allocated when we grow a vector */ - ELEMSPERCHUNK = 8 -}; - -/* - * Global NSS data structures are mostly read-only, but we update - * them when we read or re-read the nsswitch.conf. - */ -static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; - -/* - * Runtime determination of whether we are dynamically linked or not. - */ -extern int _DYNAMIC __attribute__ ((weak)); -#define is_dynamic() (&_DYNAMIC != NULL) - -/* - * default sourcelist: `files' - */ -const ns_src __nsdefaultsrc[] = { - { NSSRC_FILES, NS_SUCCESS }, - { 0 }, -}; - -/* Database, source mappings. */ -static unsigned int _nsmapsize; -static ns_dbt *_nsmap = NULL; - -/* NSS modules. */ -static unsigned int _nsmodsize; -static ns_mod *_nsmod; - -/* Placeholder for builtin modules' dlopen `handle'. */ -static int __nss_builtin_handle; -static void *nss_builtin_handle = &__nss_builtin_handle; - -#ifdef NS_CACHING -/* - * Cache lookup cycle prevention function - if !NULL then no cache lookups - * will be made - */ -static void *nss_cache_cycle_prevention_func = NULL; -#endif - -/* - * When this is set to 1, nsdispatch won't use nsswitch.conf - * but will consult the 'defaults' source list only. - * NOTE: nested fallbacks (when nsdispatch calls fallback functions, - * which in turn calls nsdispatch, which should call fallback - * function) are not supported - */ -struct fb_state { - int fb_dispatch; -}; -static void fb_endstate(void *); -NSS_TLS_HANDLING(fb); - -/* - * Attempt to spew relatively uniform messages to syslog. - */ -#define nss_log(level, fmt, ...) \ - syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__) -#define nss_log_simple(level, s) \ - syslog((level), "NSSWITCH(%s): " s, __func__) - -/* - * Dynamically growable arrays are used for lists of databases, sources, - * and modules. The following `vector' interface is used to isolate the - * common operations. - */ -typedef int (*vector_comparison)(const void *, const void *); -typedef void (*vector_free_elem)(void *); -static void vector_sort(void *, unsigned int, size_t, - vector_comparison); -static void vector_free(void *, unsigned int *, size_t, - vector_free_elem); -static void *vector_ref(unsigned int, void *, unsigned int, size_t); -static void *vector_search(const void *, void *, unsigned int, size_t, - vector_comparison); -static void *vector_append(const void *, void *, unsigned int *, size_t); - - -/* - * Internal interfaces. - */ -static int string_compare(const void *, const void *); -static int mtab_compare(const void *, const void *); -static int nss_configure(void); -static void ns_dbt_free(ns_dbt *); -static void ns_mod_free(ns_mod *); -static void ns_src_free(ns_src **, int); -static void nss_load_builtin_modules(void); -static void nss_load_module(const char *, nss_module_register_fn); -static void nss_atexit(void); -/* nsparser */ -extern FILE *_nsyyin; - - -/* - * The vector operations - */ -static void -vector_sort(void *vec, unsigned int count, size_t esize, - vector_comparison comparison) -{ - qsort(vec, count, esize, comparison); -} - - -static void * -vector_search(const void *key, void *vec, unsigned int count, size_t esize, - vector_comparison comparison) -{ - return (bsearch(key, vec, count, esize, comparison)); -} - - -static void * -vector_append(const void *elem, void *vec, unsigned int *count, size_t esize) -{ - void *p; - - if ((*count % ELEMSPERCHUNK) == 0) { - p = realloc(vec, (*count + ELEMSPERCHUNK) * esize); - if (p == NULL) { - nss_log_simple(LOG_ERR, "memory allocation failure"); - return (vec); - } - vec = p; - } - memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize); - (*count)++; - return (vec); -} - - -static void * -vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize) -{ - if (i < count) - return (void *)((uintptr_t)vec + (i * esize)); - else - return (NULL); -} - - -#define VECTOR_FREE(v, c, s, f) \ - do { vector_free(v, c, s, f); v = NULL; } while (0) -static void -vector_free(void *vec, unsigned int *count, size_t esize, - vector_free_elem free_elem) -{ - unsigned int i; - void *elem; - - for (i = 0; i < *count; i++) { - elem = vector_ref(i, vec, *count, esize); - if (elem != NULL) - free_elem(elem); - } - free(vec); - *count = 0; -} - -/* - * Comparison functions for vector_search. - */ -static int -string_compare(const void *a, const void *b) -{ - return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); -} - - -static int -mtab_compare(const void *a, const void *b) -{ - int cmp; - - cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name); - if (cmp != 0) - return (cmp); - else - return (strcmp(((const ns_mtab *)a)->database, - ((const ns_mtab *)b)->database)); -} - -/* - * NSS nsmap management. - */ -void -_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src) -{ - const ns_mod *modp; - - dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize, - sizeof(*src)); - modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod), - string_compare); - if (modp == NULL) - nss_load_module(src->name, NULL); -} - - -#ifdef _NSS_DEBUG -void -_nsdbtdump(const ns_dbt *dbt) -{ - int i; - - printf("%s (%d source%s):", dbt->name, dbt->srclistsize, - dbt->srclistsize == 1 ? "" : "s"); - for (i = 0; i < (int)dbt->srclistsize; i++) { - printf(" %s", dbt->srclist[i].name); - if (!(dbt->srclist[i].flags & - (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) && - (dbt->srclist[i].flags & NS_SUCCESS)) - continue; - printf(" ["); - if (!(dbt->srclist[i].flags & NS_SUCCESS)) - printf(" SUCCESS=continue"); - if (dbt->srclist[i].flags & NS_UNAVAIL) - printf(" UNAVAIL=return"); - if (dbt->srclist[i].flags & NS_NOTFOUND) - printf(" NOTFOUND=return"); - if (dbt->srclist[i].flags & NS_TRYAGAIN) - printf(" TRYAGAIN=return"); - printf(" ]"); - } - printf("\n"); -} -#endif - - -/* - * The first time nsdispatch is called (during a process's lifetime, - * or after nsswitch.conf has been updated), nss_configure will - * prepare global data needed by NSS. - */ -static int -nss_configure(void) -{ - static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER; - static time_t confmod; - struct stat statbuf; - int result, isthreaded; - const char *path; -#ifdef NS_CACHING - void *handle; -#endif - - result = 0; - isthreaded = __isthreaded; -#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT) - /* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built - * for debugging purposes and MUST NEVER be used in production. - */ - path = getenv("NSSWITCH_CONF"); - if (path == NULL) -#endif - path = _PATH_NS_CONF; - if (stat(path, &statbuf) != 0) - return (0); - if (statbuf.st_mtime <= confmod) - return (0); - if (isthreaded) { - result = _pthread_mutex_trylock(&conf_lock); - if (result != 0) - return (0); - (void)_pthread_rwlock_unlock(&nss_lock); - result = _pthread_rwlock_wrlock(&nss_lock); - if (result != 0) - goto fin2; - } - _nsyyin = fopen(path, "r"); - if (_nsyyin == NULL) - goto fin; - VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), - (vector_free_elem)ns_dbt_free); - VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), - (vector_free_elem)ns_mod_free); - nss_load_builtin_modules(); - _nsyyparse(); - (void)fclose(_nsyyin); - vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare); - if (confmod == 0) - (void)atexit(nss_atexit); - confmod = statbuf.st_mtime; - -#ifdef NS_CACHING - handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); - if (handle != NULL) { - nss_cache_cycle_prevention_func = dlsym(handle, - "_nss_cache_cycle_prevention_function"); - dlclose(handle); - } -#endif -fin: - if (isthreaded) { - (void)_pthread_rwlock_unlock(&nss_lock); - if (result == 0) - result = _pthread_rwlock_rdlock(&nss_lock); - } -fin2: - if (isthreaded) - (void)_pthread_mutex_unlock(&conf_lock); - return (result); -} - - -void -_nsdbtput(const ns_dbt *dbt) -{ - unsigned int i; - ns_dbt *p; - - for (i = 0; i < _nsmapsize; i++) { - p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap)); - if (string_compare(&dbt->name, &p->name) == 0) { - /* overwrite existing entry */ - if (p->srclist != NULL) - ns_src_free(&p->srclist, p->srclistsize); - memmove(p, dbt, sizeof(*dbt)); - return; - } - } - _nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap)); -} - - -static void -ns_dbt_free(ns_dbt *dbt) -{ - ns_src_free(&dbt->srclist, dbt->srclistsize); - if (dbt->name) - free((void *)dbt->name); -} - - -static void -ns_src_free(ns_src **src, int srclistsize) -{ - int i; - - for (i = 0; i < srclistsize; i++) - if ((*src)[i].name != NULL) - /* This one was allocated by nslexer. You'll just - * have to trust me. - */ - free((void *)((*src)[i].name)); - free(*src); - *src = NULL; -} - - - -/* - * NSS module management. - */ -/* The built-in NSS modules are all loaded at once. */ -#define NSS_BACKEND(name, reg) \ -ns_mtab *reg(unsigned int *, nss_module_unregister_fn *); -#include "nss_backends.h" -#undef NSS_BACKEND - -static void -nss_load_builtin_modules(void) -{ -#define NSS_BACKEND(name, reg) nss_load_module(#name, reg); -#include "nss_backends.h" -#undef NSS_BACKEND -} - - -/* Load a built-in or dynamically linked module. If the `reg_fn' - * argument is non-NULL, assume a built-in module and use reg_fn to - * register it. Otherwise, search for a dynamic NSS module. - */ -static void -nss_load_module(const char *source, nss_module_register_fn reg_fn) -{ - char buf[PATH_MAX]; - ns_mod mod; - nss_module_register_fn fn; - - memset(&mod, 0, sizeof(mod)); - mod.name = strdup(source); - if (mod.name == NULL) { - nss_log_simple(LOG_ERR, "memory allocation failure"); - return; - } - if (reg_fn != NULL) { - /* The placeholder is required, as a NULL handle - * represents an invalid module. - */ - mod.handle = nss_builtin_handle; - fn = reg_fn; - } else if (!is_dynamic()) - goto fin; - else { - if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name, - NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf)) - goto fin; - mod.handle = dlopen(buf, RTLD_LOCAL|RTLD_LAZY); - if (mod.handle == NULL) { -#ifdef _NSS_DEBUG - /* This gets pretty annoying since the built-in - * sources aren't modules yet. - */ - nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror()); -#endif - goto fin; - } - fn = (nss_module_register_fn)dlfunc(mod.handle, - "nss_module_register"); - if (fn == NULL) { - (void)dlclose(mod.handle); - mod.handle = NULL; - nss_log(LOG_ERR, "%s, %s", mod.name, dlerror()); - goto fin; - } - } - mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister); - if (mod.mtab == NULL || mod.mtabsize == 0) { - if (mod.handle != nss_builtin_handle) - (void)dlclose(mod.handle); - mod.handle = NULL; - nss_log(LOG_ERR, "%s, registration failed", mod.name); - goto fin; - } - if (mod.mtabsize > 1) - qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]), - mtab_compare); -fin: - _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); - vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); -} - - - -static void -ns_mod_free(ns_mod *mod) -{ - - free(mod->name); - if (mod->handle == NULL) - return; - if (mod->unregister != NULL) - mod->unregister(mod->mtab, mod->mtabsize); - if (mod->handle != nss_builtin_handle) - (void)dlclose(mod->handle); -} - - - -/* - * Cleanup - */ -static void -nss_atexit(void) -{ - int isthreaded; - - isthreaded = __isthreaded; - if (isthreaded) - (void)_pthread_rwlock_wrlock(&nss_lock); - VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), - (vector_free_elem)ns_dbt_free); - VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), - (vector_free_elem)ns_mod_free); - if (isthreaded) - (void)_pthread_rwlock_unlock(&nss_lock); -} - - - -/* - * Finally, the actual implementation. - */ -static nss_method -nss_method_lookup(const char *source, const char *database, - const char *method, const ns_dtab disp_tab[], void **mdata) -{ - ns_mod *mod; - ns_mtab *match, key; - int i; - - if (disp_tab != NULL) - for (i = 0; disp_tab[i].src != NULL; i++) - if (strcasecmp(source, disp_tab[i].src) == 0) { - *mdata = disp_tab[i].mdata; - return (disp_tab[i].method); - } - mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod), - string_compare); - if (mod != NULL && mod->handle != NULL) { - key.database = database; - key.name = method; - match = bsearch(&key, mod->mtab, mod->mtabsize, - sizeof(mod->mtab[0]), mtab_compare); - if (match != NULL) { - *mdata = match->mdata; - return (match->method); - } - } - - *mdata = NULL; - return (NULL); -} - -static void -fb_endstate(void *p) -{ - free(p); -} - -__weak_reference(_nsdispatch, nsdispatch); - -int -_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, - const char *method_name, const ns_src defaults[], ...) -{ - va_list ap; - const ns_dbt *dbt; - const ns_src *srclist; - nss_method method, fb_method; - void *mdata; - int isthreaded, serrno, i, result, srclistsize; - struct fb_state *st; - -#ifdef NS_CACHING - nss_cache_data cache_data; - nss_cache_data *cache_data_p; - int cache_flag; -#endif - - dbt = NULL; - fb_method = NULL; - - isthreaded = __isthreaded; - serrno = errno; - if (isthreaded) { - result = _pthread_rwlock_rdlock(&nss_lock); - if (result != 0) { - result = NS_UNAVAIL; - goto fin; - } - } - - result = fb_getstate(&st); - if (result != 0) { - result = NS_UNAVAIL; - goto fin; - } - - result = nss_configure(); - if (result != 0) { - result = NS_UNAVAIL; - goto fin; - } - if (st->fb_dispatch == 0) { - dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap), - string_compare); - fb_method = nss_method_lookup(NSSRC_FALLBACK, database, - method_name, disp_tab, &mdata); - } - - if (dbt != NULL) { - srclist = dbt->srclist; - srclistsize = dbt->srclistsize; - } else { - srclist = defaults; - srclistsize = 0; - while (srclist[srclistsize].name != NULL) - srclistsize++; - } - -#ifdef NS_CACHING - cache_data_p = NULL; - cache_flag = 0; -#endif - for (i = 0; i < srclistsize; i++) { - result = NS_NOTFOUND; - method = nss_method_lookup(srclist[i].name, database, - method_name, disp_tab, &mdata); - - if (method != NULL) { -#ifdef NS_CACHING - if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 && - nss_cache_cycle_prevention_func == NULL) { -#ifdef NS_STRICT_LIBC_EID_CHECKING - if (issetugid() != 0) - continue; -#endif - cache_flag = 1; - - memset(&cache_data, 0, sizeof(nss_cache_data)); - cache_data.info = (nss_cache_info const *)mdata; - cache_data_p = &cache_data; - - va_start(ap, defaults); - if (cache_data.info->id_func != NULL) - result = __nss_common_cache_read(retval, - cache_data_p, ap); - else if (cache_data.info->marshal_func != NULL) - result = __nss_mp_cache_read(retval, - cache_data_p, ap); - else - result = __nss_mp_cache_end(retval, - cache_data_p, ap); - va_end(ap); - } else { - cache_flag = 0; - errno = 0; - va_start(ap, defaults); - result = method(retval, mdata, ap); - va_end(ap); - } -#else /* NS_CACHING */ - errno = 0; - va_start(ap, defaults); - result = method(retval, mdata, ap); - va_end(ap); -#endif /* NS_CACHING */ - - if (result & (srclist[i].flags)) - break; - } else { - if (fb_method != NULL) { - st->fb_dispatch = 1; - va_start(ap, defaults); - result = fb_method(retval, - (void *)srclist[i].name, ap); - va_end(ap); - st->fb_dispatch = 0; - } else - nss_log(LOG_DEBUG, "%s, %s, %s, not found, " - "and no fallback provided", - srclist[i].name, database, method_name); - } - } - -#ifdef NS_CACHING - if (cache_data_p != NULL && - (result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) { - va_start(ap, defaults); - if (result == NS_SUCCESS) { - if (cache_data.info->id_func != NULL) - __nss_common_cache_write(retval, cache_data_p, - ap); - else if (cache_data.info->marshal_func != NULL) - __nss_mp_cache_write(retval, cache_data_p, ap); - } else if (result == NS_NOTFOUND) { - if (cache_data.info->id_func == NULL) { - if (cache_data.info->marshal_func != NULL) - __nss_mp_cache_write_submit(retval, - cache_data_p, ap); - } else - __nss_common_cache_write_negative(cache_data_p); - } - va_end(ap); - } -#endif /* NS_CACHING */ - - if (isthreaded) - (void)_pthread_rwlock_unlock(&nss_lock); -fin: - errno = serrno; - return (result); -} |