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