Home | History | Annotate | Line # | Download | only in net
nsdispatch.c revision 1.36.4.1
      1  1.36.4.1      yamt /*	$NetBSD: nsdispatch.c,v 1.36.4.1 2012/04/17 00:05:21 yamt Exp $	*/
      2       1.2     lukem 
      3       1.2     lukem /*-
      4      1.22   thorpej  * Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
      5       1.2     lukem  * All rights reserved.
      6       1.2     lukem  *
      7       1.2     lukem  * This code is derived from software contributed to The NetBSD Foundation
      8      1.22   thorpej  * by Luke Mewburn; and by Jason R. Thorpe.
      9       1.2     lukem  *
     10       1.2     lukem  * Redistribution and use in source and binary forms, with or without
     11       1.2     lukem  * modification, are permitted provided that the following conditions
     12       1.2     lukem  * are met:
     13       1.2     lukem  * 1. Redistributions of source code must retain the above copyright
     14       1.2     lukem  *    notice, this list of conditions and the following disclaimer.
     15       1.2     lukem  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.2     lukem  *    notice, this list of conditions and the following disclaimer in the
     17       1.2     lukem  *    documentation and/or other materials provided with the distribution.
     18       1.2     lukem  *
     19       1.2     lukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.2     lukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.2     lukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.2     lukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.2     lukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.2     lukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.2     lukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.2     lukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.2     lukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.2     lukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.2     lukem  * POSSIBILITY OF SUCH DAMAGE.
     30       1.2     lukem  */
     31       1.9     lukem 
     32      1.22   thorpej /*-
     33      1.22   thorpej  * Copyright (c) 2003 Networks Associates Technology, Inc.
     34      1.22   thorpej  * All rights reserved.
     35      1.22   thorpej  *
     36      1.22   thorpej  * Portions of this software were developed for the FreeBSD Project by
     37      1.22   thorpej  * Jacques A. Vidrine, Safeport Network Services, and Network
     38      1.22   thorpej  * Associates Laboratories, the Security Research Division of Network
     39      1.22   thorpej  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
     40      1.22   thorpej  * ("CBOSS"), as part of the DARPA CHATS research program.
     41      1.22   thorpej  *
     42      1.22   thorpej  * Redistribution and use in source and binary forms, with or without
     43      1.22   thorpej  * modification, are permitted provided that the following conditions
     44      1.22   thorpej  * are met:
     45      1.22   thorpej  * 1. Redistributions of source code must retain the above copyright
     46      1.22   thorpej  *    notice, this list of conditions and the following disclaimer.
     47      1.22   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     48      1.22   thorpej  *    notice, this list of conditions and the following disclaimer in the
     49      1.22   thorpej  *    documentation and/or other materials provided with the distribution.
     50      1.22   thorpej  *
     51      1.22   thorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     52      1.22   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53      1.22   thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54      1.22   thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     55      1.22   thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56      1.22   thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57      1.22   thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58      1.22   thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59      1.22   thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60      1.22   thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61      1.22   thorpej  * SUCH DAMAGE.
     62      1.22   thorpej  */
     63      1.22   thorpej 
     64       1.9     lukem #include <sys/cdefs.h>
     65       1.9     lukem #if defined(LIBC_SCCS) && !defined(lint)
     66  1.36.4.1      yamt __RCSID("$NetBSD: nsdispatch.c,v 1.36.4.1 2012/04/17 00:05:21 yamt Exp $");
     67       1.9     lukem #endif /* LIBC_SCCS and not lint */
     68       1.2     lukem 
     69       1.6     lukem #include "namespace.h"
     70       1.6     lukem 
     71       1.2     lukem #include <sys/types.h>
     72       1.2     lukem #include <sys/param.h>
     73       1.2     lukem #include <sys/stat.h>
     74      1.23   thorpej #include <sys/queue.h>
     75       1.2     lukem 
     76      1.12     lukem #include <assert.h>
     77      1.22   thorpej #ifdef __ELF__
     78      1.22   thorpej #include <dlfcn.h>
     79      1.22   thorpej #endif /* __ELF__ */
     80       1.2     lukem #include <err.h>
     81       1.2     lukem #include <fcntl.h>
     82       1.2     lukem #define _NS_PRIVATE
     83       1.2     lukem #include <nsswitch.h>
     84      1.18       wiz #include <stdarg.h>
     85       1.2     lukem #include <stdio.h>
     86       1.2     lukem #include <stdlib.h>
     87       1.2     lukem #include <string.h>
     88       1.2     lukem #include <unistd.h>
     89      1.22   thorpej 
     90      1.22   thorpej #include "reentrant.h"
     91      1.10     lukem 
     92      1.17  christos extern	FILE 	*_nsyyin;
     93      1.21   thorpej extern	int	 _nsyyparse(void);
     94      1.17  christos 
     95      1.17  christos 
     96       1.6     lukem #ifdef __weak_alias
     97      1.16   mycroft __weak_alias(nsdispatch,_nsdispatch)
     98       1.6     lukem #endif
     99       1.2     lukem 
    100       1.2     lukem 
    101       1.5     lukem /*
    102       1.5     lukem  * default sourcelist: `files'
    103       1.5     lukem  */
    104       1.5     lukem const ns_src __nsdefaultsrc[] = {
    105      1.28     lukem 	{ NSSRC_FILES,	NS_SUCCESS },
    106      1.31  christos 	{ 0, 0 },
    107       1.5     lukem };
    108       1.5     lukem 
    109      1.28     lukem const ns_src __nsdefaultcompat[] = {
    110      1.28     lukem 	{ NSSRC_COMPAT,	NS_SUCCESS },
    111      1.31  christos 	{ 0, 0 }
    112      1.28     lukem };
    113      1.28     lukem 
    114      1.28     lukem const ns_src __nsdefaultcompat_forceall[] = {
    115      1.28     lukem 	{ NSSRC_COMPAT,	NS_SUCCESS | NS_FORCEALL },
    116      1.31  christos 	{ 0, 0 }
    117      1.28     lukem };
    118      1.28     lukem 
    119      1.28     lukem const ns_src __nsdefaultfiles[] = {
    120      1.28     lukem 	{ NSSRC_FILES,	NS_SUCCESS },
    121      1.31  christos 	{ 0, 0 },
    122      1.28     lukem };
    123      1.28     lukem 
    124      1.28     lukem const ns_src __nsdefaultfiles_forceall[] = {
    125      1.28     lukem 	{ NSSRC_FILES,	NS_SUCCESS | NS_FORCEALL },
    126      1.31  christos 	{ 0, 0 },
    127      1.28     lukem };
    128      1.28     lukem 
    129      1.28     lukem const ns_src __nsdefaultnis[] = {
    130      1.28     lukem 	{ NSSRC_NIS,	NS_SUCCESS },
    131      1.31  christos 	{ 0, 0 }
    132      1.28     lukem };
    133      1.28     lukem 
    134      1.28     lukem const ns_src __nsdefaultnis_forceall[] = {
    135      1.28     lukem 	{ NSSRC_NIS,	NS_SUCCESS | NS_FORCEALL },
    136      1.31  christos 	{ 0, 0 }
    137      1.28     lukem };
    138      1.28     lukem 
    139      1.28     lukem 
    140      1.22   thorpej /* Database, source mappings. */
    141      1.22   thorpej static	u_int			 _nsmapsize;
    142      1.22   thorpej static	ns_dbt			*_nsmap;
    143      1.22   thorpej 
    144      1.22   thorpej /* Nsswitch modules. */
    145      1.22   thorpej static	u_int			 _nsmodsize;
    146      1.22   thorpej static	ns_mod			*_nsmod;
    147      1.22   thorpej 
    148      1.22   thorpej /* Placeholder for built-in modules' dlopen() handles. */
    149      1.22   thorpej static	void			*_nsbuiltin = &_nsbuiltin;
    150       1.5     lukem 
    151      1.19  christos #ifdef _REENTRANT
    152      1.22   thorpej /*
    153      1.22   thorpej  * Global nsswitch data structures are mostly read-only, but we update them
    154      1.22   thorpej  * when we read or re-read nsswitch.conf.
    155      1.22   thorpej  */
    156      1.22   thorpej static 	rwlock_t		_nslock = RWLOCK_INITIALIZER;
    157      1.23   thorpej 
    158      1.23   thorpej /*
    159      1.23   thorpej  * List of threads currently in nsdispatch().  We use this to detect
    160      1.23   thorpej  * recursive calls and avoid reloading configuration in such cases,
    161      1.23   thorpej  * which could cause deadlock.
    162      1.23   thorpej  */
    163      1.23   thorpej struct _ns_drec {
    164      1.23   thorpej 	LIST_ENTRY(_ns_drec)	list;
    165      1.23   thorpej 	thr_t			thr;
    166      1.23   thorpej };
    167      1.23   thorpej static LIST_HEAD(, _ns_drec) _ns_drec = LIST_HEAD_INITIALIZER(&_ns_drec);
    168      1.23   thorpej static mutex_t _ns_drec_lock = MUTEX_INITIALIZER;
    169      1.23   thorpej #endif /* _REENTRANT */
    170      1.22   thorpej 
    171      1.22   thorpej 
    172      1.22   thorpej /*
    173      1.22   thorpej  * Runtime determination of whether we are dynamically linked or not.
    174      1.22   thorpej  */
    175      1.35     joerg #ifndef __ELF__
    176      1.35     joerg #define	is_dynamic()		(0)	/* don't bother - switch to ELF! */
    177      1.36     joerg #else
    178      1.36     joerg __weakref_visible int rtld_DYNAMIC __weak_reference(_DYNAMIC);
    179      1.35     joerg #define	is_dynamic()		(&rtld_DYNAMIC != NULL)
    180      1.35     joerg #endif
    181      1.19  christos 
    182       1.2     lukem 
    183       1.2     lukem /*
    184      1.22   thorpej  * size of dynamic array chunk for _nsmap and _nsmap[x].srclist (and other
    185      1.22   thorpej  * growing arrays).
    186       1.2     lukem  */
    187       1.2     lukem #define NSELEMSPERCHUNK		8
    188       1.2     lukem 
    189      1.22   thorpej /*
    190      1.22   thorpej  * Dynamically growable arrays are used for lists of databases, sources,
    191      1.22   thorpej  * and modules.  The following "vector" API is used to isolate the
    192      1.22   thorpej  * common operations.
    193      1.22   thorpej  */
    194      1.22   thorpej typedef void	(*_nsvect_free_elem)(void *);
    195      1.22   thorpej 
    196      1.22   thorpej static void *
    197      1.22   thorpej _nsvect_append(const void *elem, void *vec, u_int *count, size_t esize)
    198      1.22   thorpej {
    199      1.22   thorpej 	void	*p;
    200      1.22   thorpej 
    201      1.22   thorpej 	if ((*count % NSELEMSPERCHUNK) == 0) {
    202      1.22   thorpej 		p = realloc(vec, (*count + NSELEMSPERCHUNK) * esize);
    203      1.22   thorpej 		if (p == NULL)
    204      1.22   thorpej 			return (NULL);
    205      1.22   thorpej 		vec = p;
    206      1.22   thorpej 	}
    207      1.22   thorpej 	memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize);
    208      1.22   thorpej 	(*count)++;
    209      1.22   thorpej 	return (vec);
    210      1.22   thorpej }
    211      1.22   thorpej 
    212      1.22   thorpej static void *
    213      1.22   thorpej _nsvect_elem(u_int i, void *vec, u_int count, size_t esize)
    214      1.22   thorpej {
    215      1.22   thorpej 
    216      1.22   thorpej 	if (i < count)
    217      1.22   thorpej 		return ((void *)((uintptr_t)vec + (i * esize)));
    218      1.22   thorpej 	else
    219      1.22   thorpej 		return (NULL);
    220      1.22   thorpej }
    221      1.22   thorpej 
    222      1.22   thorpej static void
    223      1.22   thorpej _nsvect_free(void *vec, u_int *count, size_t esize, _nsvect_free_elem free_elem)
    224      1.22   thorpej {
    225      1.22   thorpej 	void	*elem;
    226      1.22   thorpej 	u_int	 i;
    227      1.22   thorpej 
    228      1.22   thorpej 	for (i = 0; i < *count; i++) {
    229      1.22   thorpej 		elem = _nsvect_elem(i, vec, *count, esize);
    230      1.22   thorpej 		if (elem != NULL)
    231      1.22   thorpej 			(*free_elem)(elem);
    232      1.22   thorpej 	}
    233      1.22   thorpej 	if (vec != NULL)
    234      1.22   thorpej 		free(vec);
    235      1.22   thorpej 	*count = 0;
    236      1.22   thorpej }
    237      1.22   thorpej #define	_NSVECT_FREE(v, c, s, f)					\
    238      1.22   thorpej do {									\
    239      1.22   thorpej 	_nsvect_free((v), (c), (s), (f));				\
    240      1.22   thorpej 	(v) = NULL;							\
    241      1.22   thorpej } while (/*CONSTCOND*/0)
    242       1.2     lukem 
    243      1.21   thorpej static int
    244      1.22   thorpej _nsdbtcmp(const void *a, const void *b)
    245       1.2     lukem {
    246      1.22   thorpej 
    247       1.7  christos 	return (strcasecmp(((const ns_dbt *)a)->name,
    248       1.7  christos 	    ((const ns_dbt *)b)->name));
    249       1.2     lukem }
    250       1.2     lukem 
    251      1.22   thorpej static int
    252      1.22   thorpej _nsmodcmp(const void *a, const void *b)
    253      1.22   thorpej {
    254      1.22   thorpej 
    255      1.22   thorpej 	return (strcasecmp(((const ns_mod *)a)->name,
    256      1.22   thorpej 	    ((const ns_mod *)b)->name));
    257      1.22   thorpej }
    258      1.22   thorpej 
    259      1.22   thorpej static int
    260      1.22   thorpej _nsmtabcmp(const void *a, const void *b)
    261      1.22   thorpej {
    262      1.22   thorpej 	int	cmp;
    263      1.22   thorpej 
    264      1.22   thorpej 	cmp = strcmp(((const ns_mtab *)a)->name,
    265      1.22   thorpej 	    ((const ns_mtab *)b)->name);
    266      1.22   thorpej 	if (cmp)
    267      1.22   thorpej 		return (cmp);
    268      1.22   thorpej 
    269      1.22   thorpej 	return (strcasecmp(((const ns_mtab *)a)->database,
    270      1.22   thorpej 	    ((const ns_mtab *)b)->database));
    271      1.22   thorpej }
    272      1.22   thorpej 
    273      1.22   thorpej static void
    274      1.22   thorpej _nsmodfree(ns_mod *mod)
    275      1.22   thorpej {
    276      1.22   thorpej 
    277      1.30  christos 	free(__UNCONST(mod->name));
    278      1.22   thorpej 	if (mod->handle == NULL)
    279      1.22   thorpej 		return;
    280      1.22   thorpej 	if (mod->unregister != NULL)
    281      1.22   thorpej 		(*mod->unregister)(mod->mtab, mod->mtabsize);
    282      1.22   thorpej #ifdef __ELF__
    283      1.22   thorpej 	if (mod->handle != _nsbuiltin)
    284      1.22   thorpej 		(void) dlclose(mod->handle);
    285      1.22   thorpej #endif /* __ELF__ */
    286      1.22   thorpej }
    287      1.22   thorpej 
    288      1.22   thorpej /*
    289      1.22   thorpej  * Load a built-in or dyanamically linked module.  If the `reg_fn'
    290      1.22   thorpej  * argument is non-NULL, assume a built-in module and use `reg_fn'
    291      1.22   thorpej  * to register it.  Otherwise, search for a dynamic nsswitch module.
    292      1.22   thorpej  */
    293      1.22   thorpej static int
    294      1.22   thorpej _nsloadmod(const char *source, nss_module_register_fn reg_fn)
    295      1.22   thorpej {
    296      1.24    simonb #ifdef __ELF__
    297      1.22   thorpej 	char	buf[PATH_MAX];
    298      1.24    simonb #endif
    299      1.22   thorpej 	ns_mod	mod, *new;
    300      1.22   thorpej 
    301      1.22   thorpej 	memset(&mod, 0, sizeof(mod));
    302      1.22   thorpej 	mod.name = strdup(source);
    303      1.22   thorpej 	if (mod.name == NULL)
    304      1.22   thorpej 		return (-1);
    305      1.22   thorpej 
    306      1.22   thorpej 	if (reg_fn != NULL) {
    307      1.22   thorpej 		/*
    308      1.22   thorpej 		 * The placeholder is required, as a NULL handle
    309      1.22   thorpej 		 * represents an invalid module.
    310      1.22   thorpej 		 */
    311      1.22   thorpej 		mod.handle = _nsbuiltin;
    312      1.22   thorpej 	} else if (!is_dynamic()) {
    313      1.22   thorpej 		goto out;
    314      1.22   thorpej 	} else {
    315      1.22   thorpej #ifdef __ELF__
    316      1.22   thorpej 		if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
    317      1.22   thorpej 		    NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
    318      1.22   thorpej 			goto out;
    319      1.22   thorpej 		mod.handle = dlopen(buf, RTLD_LOCAL | RTLD_LAZY);
    320      1.22   thorpej 		if (mod.handle == NULL) {
    321      1.22   thorpej #ifdef _NSS_DEBUG
    322      1.22   thorpej 			/*
    323      1.22   thorpej 			 * This gets pretty annoying, since the built-in
    324      1.22   thorpej 			 * sources are not yet modules.
    325      1.22   thorpej 			 */
    326      1.22   thorpej 			/* XXX log some error? */
    327      1.22   thorpej #endif
    328      1.22   thorpej 			goto out;
    329      1.22   thorpej 		}
    330      1.22   thorpej 		reg_fn = (nss_module_register_fn) dlsym(mod.handle,
    331      1.22   thorpej 		    "nss_module_register");
    332      1.22   thorpej 		if (reg_fn == NULL) {
    333      1.22   thorpej 			(void) dlclose(mod.handle);
    334      1.22   thorpej 			mod.handle = NULL;
    335      1.22   thorpej 			/* XXX log some error? */
    336      1.22   thorpej 			goto out;
    337      1.22   thorpej 		}
    338      1.22   thorpej #else /* ! __ELF__ */
    339      1.22   thorpej 		mod.handle = NULL;
    340      1.22   thorpej #endif /* __ELF__ */
    341      1.22   thorpej 	}
    342      1.22   thorpej 	mod.mtab = (*reg_fn)(mod.name, &mod.mtabsize, &mod.unregister);
    343      1.22   thorpej 	if (mod.mtab == NULL || mod.mtabsize == 0) {
    344      1.22   thorpej #ifdef __ELF__
    345      1.22   thorpej 		if (mod.handle != _nsbuiltin)
    346      1.22   thorpej 			(void) dlclose(mod.handle);
    347      1.22   thorpej #endif /* __ELF__ */
    348      1.22   thorpej 		mod.handle = NULL;
    349      1.22   thorpej 		/* XXX log some error? */
    350      1.22   thorpej 		goto out;
    351      1.22   thorpej 	}
    352      1.22   thorpej 	if (mod.mtabsize > 1)
    353      1.22   thorpej 		qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
    354      1.22   thorpej 		    _nsmtabcmp);
    355      1.22   thorpej  out:
    356      1.22   thorpej 	new = _nsvect_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod));
    357      1.22   thorpej 	if (new == NULL) {
    358      1.22   thorpej 		_nsmodfree(&mod);
    359      1.22   thorpej 		return (-1);
    360      1.22   thorpej 	}
    361      1.22   thorpej 	_nsmod = new;
    362      1.22   thorpej 	/* _nsmodsize already incremented */
    363      1.22   thorpej 
    364      1.22   thorpej 	qsort(_nsmod, _nsmodsize, sizeof(*_nsmod), _nsmodcmp);
    365      1.22   thorpej 	return (0);
    366      1.22   thorpej }
    367      1.22   thorpej 
    368      1.22   thorpej static void
    369      1.22   thorpej _nsloadbuiltin(void)
    370      1.22   thorpej {
    371      1.22   thorpej 
    372      1.22   thorpej 	/* Do nothing, for now. */
    373      1.22   thorpej }
    374       1.2     lukem 
    375      1.15     lukem int
    376      1.21   thorpej _nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
    377       1.2     lukem {
    378      1.22   thorpej 	void		*new;
    379      1.22   thorpej 	const ns_mod	*mod;
    380      1.22   thorpej 	ns_mod		 modkey;
    381      1.12     lukem 
    382      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    383      1.12     lukem 	_DIAGASSERT(src != NULL);
    384      1.12     lukem 
    385      1.22   thorpej 	new = _nsvect_append(src, dbt->srclist, &dbt->srclistsize,
    386      1.22   thorpej 	    sizeof(*src));
    387      1.22   thorpej 	if (new == NULL)
    388      1.22   thorpej 		return (-1);
    389      1.22   thorpej 	dbt->srclist = new;
    390      1.22   thorpej 	/* dbt->srclistsize already incremented */
    391      1.22   thorpej 
    392      1.22   thorpej 	modkey.name = src->name;
    393  1.36.4.1      yamt 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod), _nsmodcmp);
    394      1.22   thorpej 	if (mod == NULL)
    395      1.22   thorpej 		return (_nsloadmod(src->name, NULL));
    396      1.15     lukem 
    397      1.15     lukem 	return (0);
    398       1.2     lukem }
    399       1.2     lukem 
    400       1.2     lukem void
    401      1.21   thorpej _nsdbtdump(const ns_dbt *dbt)
    402       1.2     lukem {
    403      1.34     lukem 	unsigned int	i;
    404       1.2     lukem 
    405      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    406      1.12     lukem 
    407       1.2     lukem 	printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
    408       1.2     lukem 	    dbt->srclistsize == 1 ? "" : "s");
    409       1.2     lukem 	for (i = 0; i < dbt->srclistsize; i++) {
    410       1.2     lukem 		printf(" %s", dbt->srclist[i].name);
    411       1.2     lukem 		if (!(dbt->srclist[i].flags &
    412       1.2     lukem 		    (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
    413       1.2     lukem 		    (dbt->srclist[i].flags & NS_SUCCESS))
    414       1.2     lukem 			continue;
    415       1.2     lukem 		printf(" [");
    416       1.2     lukem 		if (!(dbt->srclist[i].flags & NS_SUCCESS))
    417       1.2     lukem 			printf(" SUCCESS=continue");
    418       1.2     lukem 		if (dbt->srclist[i].flags & NS_UNAVAIL)
    419       1.2     lukem 			printf(" UNAVAIL=return");
    420       1.2     lukem 		if (dbt->srclist[i].flags & NS_NOTFOUND)
    421       1.2     lukem 			printf(" NOTFOUND=return");
    422       1.2     lukem 		if (dbt->srclist[i].flags & NS_TRYAGAIN)
    423       1.2     lukem 			printf(" TRYAGAIN=return");
    424       1.2     lukem 		printf(" ]");
    425       1.2     lukem 	}
    426       1.2     lukem 	printf("\n");
    427       1.2     lukem }
    428       1.2     lukem 
    429      1.22   thorpej static void
    430      1.22   thorpej _nssrclist_free(ns_src **src, u_int srclistsize)
    431       1.2     lukem {
    432      1.22   thorpej 	u_int	i;
    433       1.2     lukem 
    434      1.22   thorpej 	for (i = 0; i < srclistsize; i++) {
    435      1.30  christos 		if ((*src)[i].name != NULL)
    436      1.30  christos 			free(__UNCONST((*src)[i].name));
    437      1.22   thorpej 	}
    438      1.22   thorpej 	free(*src);
    439      1.22   thorpej 	*src = NULL;
    440      1.22   thorpej }
    441       1.2     lukem 
    442      1.22   thorpej static void
    443      1.22   thorpej _nsdbtfree(ns_dbt *dbt)
    444      1.22   thorpej {
    445       1.2     lukem 
    446      1.22   thorpej 	_nssrclist_free(&dbt->srclist, dbt->srclistsize);
    447      1.30  christos 	if (dbt->name != NULL)
    448      1.30  christos 		free(__UNCONST(dbt->name));
    449       1.2     lukem }
    450       1.2     lukem 
    451      1.15     lukem int
    452      1.21   thorpej _nsdbtput(const ns_dbt *dbt)
    453       1.2     lukem {
    454      1.22   thorpej 	ns_dbt	*p;
    455      1.22   thorpej 	void	*new;
    456      1.22   thorpej 	u_int	i;
    457       1.2     lukem 
    458      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    459      1.12     lukem 
    460       1.2     lukem 	for (i = 0; i < _nsmapsize; i++) {
    461      1.22   thorpej 		p = _nsvect_elem(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
    462      1.22   thorpej 		if (strcasecmp(dbt->name, p->name) == 0) {
    463       1.2     lukem 					/* overwrite existing entry */
    464      1.22   thorpej 			if (p->srclist != NULL)
    465      1.22   thorpej 				_nssrclist_free(&p->srclist, p->srclistsize);
    466      1.22   thorpej 			memmove(p, dbt, sizeof(*dbt));
    467      1.15     lukem 			return (0);
    468       1.2     lukem 		}
    469       1.2     lukem 	}
    470      1.22   thorpej 	new = _nsvect_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap));
    471      1.22   thorpej 	if (new == NULL)
    472      1.22   thorpej 		return (-1);
    473      1.22   thorpej 	_nsmap = new;
    474      1.22   thorpej 	/* _nsmapsize already incremented */
    475       1.2     lukem 
    476      1.22   thorpej 	return (0);
    477      1.22   thorpej }
    478      1.22   thorpej 
    479      1.22   thorpej /*
    480      1.22   thorpej  * This function is called each time nsdispatch() is called.  If this
    481      1.22   thorpej  * is the first call, or if the configuration has changed, (re-)prepare
    482      1.22   thorpej  * the global data used by NSS.
    483      1.22   thorpej  */
    484      1.22   thorpej static int
    485      1.22   thorpej _nsconfigure(void)
    486      1.22   thorpej {
    487      1.22   thorpej #ifdef _REENTRANT
    488      1.22   thorpej 	static mutex_t	_nsconflock = MUTEX_INITIALIZER;
    489      1.22   thorpej #endif
    490      1.22   thorpej 	static time_t	_nsconfmod;
    491      1.22   thorpej 	struct stat	statbuf;
    492      1.15     lukem 
    493      1.22   thorpej 	mutex_lock(&_nsconflock);
    494      1.22   thorpej 
    495      1.22   thorpej 	if (stat(_PATH_NS_CONF, &statbuf) == -1) {
    496      1.22   thorpej 		/*
    497      1.22   thorpej 		 * No nsswitch.conf; just use whatever configuration we
    498      1.22   thorpej 		 * currently have, or fall back on the defaults specified
    499      1.22   thorpej 		 * by the caller.
    500      1.22   thorpej 		 */
    501      1.22   thorpej 		mutex_unlock(&_nsconflock);
    502      1.22   thorpej 		return (0);
    503      1.22   thorpej 	}
    504      1.22   thorpej 
    505      1.22   thorpej 	if (statbuf.st_mtime <= _nsconfmod) {
    506      1.22   thorpej 		/* Internal state is up-to-date with nsswitch.conf. */
    507      1.22   thorpej 		mutex_unlock(&_nsconflock);
    508      1.22   thorpej 		return (0);
    509      1.22   thorpej 	}
    510      1.22   thorpej 
    511      1.22   thorpej 	/*
    512      1.22   thorpej 	 * Ok, we've decided we need to update the nsswitch configuration
    513      1.23   thorpej 	 * structures.  Acquire a write-lock on _nslock while continuing
    514      1.23   thorpej 	 * to hold _nsconflock.  Acquiring a write-lock blocks while
    515      1.23   thorpej 	 * waiting for other threads already holding a read-lock to clear.
    516      1.23   thorpej 	 * We hold _nsconflock for the duration, and update the time stamp
    517      1.23   thorpej 	 * at the end of the update operation, at which time we release
    518      1.23   thorpej 	 * both locks.
    519      1.22   thorpej 	 */
    520      1.22   thorpej 	rwlock_wrlock(&_nslock);
    521      1.22   thorpej 
    522      1.22   thorpej 	_nsyyin = fopen(_PATH_NS_CONF, "r");
    523      1.22   thorpej 	if (_nsyyin == NULL) {
    524      1.22   thorpej 		/*
    525      1.22   thorpej 		 * Unable to open nsswitch.conf; behave as though the
    526      1.22   thorpej 		 * stat() above failed.  Even though we have already
    527      1.22   thorpej 		 * updated _nsconfmod, if the file reappears, the
    528      1.22   thorpej 		 * mtime will change.
    529      1.22   thorpej 		 */
    530      1.23   thorpej 		goto out;
    531       1.2     lukem 	}
    532      1.22   thorpej 
    533      1.22   thorpej 	_NSVECT_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
    534      1.22   thorpej 	    (_nsvect_free_elem) _nsdbtfree);
    535      1.22   thorpej 	_NSVECT_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
    536      1.22   thorpej 	    (_nsvect_free_elem) _nsmodfree);
    537      1.22   thorpej 
    538      1.22   thorpej 	_nsloadbuiltin();
    539      1.22   thorpej 
    540      1.22   thorpej 	_nsyyparse();
    541      1.22   thorpej 	(void) fclose(_nsyyin);
    542      1.22   thorpej 	if (_nsmapsize != 0)
    543      1.22   thorpej 		qsort(_nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    544      1.23   thorpej 
    545      1.23   thorpej 	_nsconfmod = statbuf.st_mtime;
    546      1.23   thorpej 
    547      1.23   thorpej  out:
    548      1.22   thorpej 	rwlock_unlock(&_nslock);
    549      1.23   thorpej 	mutex_unlock(&_nsconflock);
    550      1.15     lukem 	return (0);
    551       1.2     lukem }
    552       1.2     lukem 
    553      1.22   thorpej static nss_method
    554      1.22   thorpej _nsmethod(const char *source, const char *database, const char *method,
    555      1.22   thorpej     const ns_dtab disp_tab[], void **cb_data)
    556      1.22   thorpej {
    557      1.22   thorpej 	int	curdisp;
    558      1.22   thorpej 	ns_mod	*mod, modkey;
    559      1.22   thorpej 	ns_mtab	*mtab, mtabkey;
    560      1.22   thorpej 
    561      1.22   thorpej 	if (disp_tab != NULL) {
    562      1.22   thorpej 		for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) {
    563      1.22   thorpej 			if (strcasecmp(source, disp_tab[curdisp].src) == 0) {
    564      1.22   thorpej 				*cb_data = disp_tab[curdisp].cb_data;
    565      1.22   thorpej 				return (disp_tab[curdisp].callback);
    566      1.22   thorpej 			}
    567      1.22   thorpej 		}
    568      1.22   thorpej 	}
    569      1.22   thorpej 
    570      1.22   thorpej 	modkey.name = source;
    571      1.22   thorpej 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod),
    572      1.22   thorpej 	    _nsmodcmp);
    573      1.22   thorpej 	if (mod != NULL && mod->handle != NULL) {
    574      1.22   thorpej 		mtabkey.database = database;
    575      1.22   thorpej 		mtabkey.name = method;
    576      1.22   thorpej 		mtab = bsearch(&mtabkey, mod->mtab, mod->mtabsize,
    577      1.22   thorpej 		    sizeof(mod->mtab[0]), _nsmtabcmp);
    578      1.22   thorpej 		if (mtab != NULL) {
    579      1.22   thorpej 			*cb_data = mtab->mdata;
    580      1.22   thorpej 			return (mtab->method);
    581      1.22   thorpej 		}
    582      1.22   thorpej 	}
    583      1.22   thorpej 
    584      1.22   thorpej 	*cb_data = NULL;
    585      1.22   thorpej 	return (NULL);
    586      1.22   thorpej }
    587       1.2     lukem 
    588       1.2     lukem int
    589      1.11  christos /*ARGSUSED*/
    590       1.5     lukem nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
    591       1.5     lukem 	    const char *method, const ns_src defaults[], ...)
    592       1.2     lukem {
    593      1.23   thorpej 	static int	 _nsdispatching;
    594      1.23   thorpej #ifdef _REENTRANT
    595      1.23   thorpej 	struct _ns_drec	 drec, *ldrec;
    596      1.23   thorpej #endif
    597       1.2     lukem 	va_list		 ap;
    598      1.22   thorpej 	int		 i, result;
    599      1.22   thorpej 	ns_dbt		 key;
    600       1.2     lukem 	const ns_dbt	*dbt;
    601       1.5     lukem 	const ns_src	*srclist;
    602       1.5     lukem 	int		 srclistsize;
    603      1.22   thorpej 	nss_method	 cb;
    604      1.22   thorpej 	void		*cb_data;
    605      1.12     lukem 
    606      1.25     lukem 	/* retval may be NULL */
    607      1.25     lukem 	/* disp_tab may be NULL */
    608      1.12     lukem 	_DIAGASSERT(database != NULL);
    609      1.12     lukem 	_DIAGASSERT(method != NULL);
    610      1.25     lukem 	_DIAGASSERT(defaults != NULL);
    611      1.25     lukem 	if (database == NULL || method == NULL || defaults == NULL)
    612      1.12     lukem 		return (NS_UNAVAIL);
    613       1.2     lukem 
    614      1.23   thorpej 	/*
    615      1.23   thorpej 	 * In both the threaded and non-threaded cases, avoid reloading
    616      1.23   thorpej 	 * the configuration if the current thread is already running
    617      1.23   thorpej 	 * nsdispatch() (i.e. recursive call).
    618      1.23   thorpej 	 *
    619      1.23   thorpej 	 * In the non-threaded case, this avoids changing the data structures
    620      1.23   thorpej 	 * while we're using them.
    621      1.23   thorpej 	 *
    622      1.23   thorpej 	 * In the threaded case, this avoids trying to take a write lock
    623      1.23   thorpej 	 * while the current thread holds a read lock (which would result
    624      1.23   thorpej 	 * in deadlock).
    625      1.23   thorpej 	 */
    626      1.23   thorpej #ifdef _REENTRANT
    627      1.23   thorpej 	if (__isthreaded) {
    628      1.23   thorpej 		drec.thr = thr_self();
    629      1.23   thorpej 		mutex_lock(&_ns_drec_lock);
    630      1.23   thorpej 		LIST_FOREACH(ldrec, &_ns_drec, list) {
    631      1.23   thorpej 			if (ldrec->thr == drec.thr)
    632      1.23   thorpej 				break;
    633      1.23   thorpej 		}
    634      1.23   thorpej 		LIST_INSERT_HEAD(&_ns_drec, &drec, list);
    635      1.23   thorpej 		mutex_unlock(&_ns_drec_lock);
    636      1.23   thorpej 		if (ldrec == NULL && _nsconfigure()) {
    637      1.23   thorpej 			mutex_lock(&_ns_drec_lock);
    638      1.23   thorpej 			LIST_REMOVE(&drec, list);
    639      1.23   thorpej 			mutex_unlock(&_ns_drec_lock);
    640      1.23   thorpej 			return (NS_UNAVAIL);
    641      1.23   thorpej 		}
    642      1.29   thorpej 	} else
    643      1.29   thorpej #endif /* _REENTRANT */
    644      1.29   thorpej 	if (_nsdispatching++ == 0 && _nsconfigure()) {
    645      1.29   thorpej 		_nsdispatching--;
    646      1.29   thorpej 		return (NS_UNAVAIL);
    647      1.23   thorpej 	}
    648      1.22   thorpej 
    649      1.22   thorpej 	rwlock_rdlock(&_nslock);
    650      1.22   thorpej 
    651      1.22   thorpej 	key.name = database;
    652      1.22   thorpej 	dbt = bsearch(&key, _nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    653       1.5     lukem 	if (dbt != NULL) {
    654       1.5     lukem 		srclist = dbt->srclist;
    655       1.5     lukem 		srclistsize = dbt->srclistsize;
    656       1.5     lukem 	} else {
    657       1.5     lukem 		srclist = defaults;
    658       1.5     lukem 		srclistsize = 0;
    659       1.5     lukem 		while (srclist[srclistsize].name != NULL)
    660       1.5     lukem 			srclistsize++;
    661       1.5     lukem 	}
    662       1.2     lukem 	result = 0;
    663       1.2     lukem 
    664       1.5     lukem 	for (i = 0; i < srclistsize; i++) {
    665      1.22   thorpej 		cb = _nsmethod(srclist[i].name, database, method,
    666      1.22   thorpej 		    disp_tab, &cb_data);
    667       1.2     lukem 		result = 0;
    668      1.22   thorpej 		if (cb != NULL) {
    669       1.5     lukem 			va_start(ap, defaults);
    670      1.22   thorpej 			result = (*cb)(retval, cb_data, ap);
    671       1.2     lukem 			va_end(ap);
    672      1.26     lukem 			if (defaults[0].flags & NS_FORCEALL)
    673      1.26     lukem 				continue;
    674      1.22   thorpej 			if (result & srclist[i].flags)
    675       1.2     lukem 				break;
    676       1.2     lukem 		}
    677       1.2     lukem 	}
    678      1.27     lukem 	result &= NS_STATUSMASK;	/* clear private flags in result */
    679      1.22   thorpej 
    680      1.22   thorpej 	rwlock_unlock(&_nslock);
    681      1.22   thorpej 
    682      1.23   thorpej #ifdef _REENTRANT
    683      1.23   thorpej 	if (__isthreaded) {
    684      1.23   thorpej 		mutex_lock(&_ns_drec_lock);
    685      1.23   thorpej 		LIST_REMOVE(&drec, list);
    686      1.23   thorpej 		mutex_unlock(&_ns_drec_lock);
    687      1.23   thorpej 	} else
    688      1.23   thorpej #endif /* _REENTRANT */
    689      1.29   thorpej 		_nsdispatching--;
    690      1.23   thorpej 
    691       1.2     lukem 	return (result ? result : NS_NOTFOUND);
    692       1.2     lukem }
    693