Home | History | Annotate | Line # | Download | only in net
nsdispatch.c revision 1.22
      1  1.22   thorpej /*	$NetBSD: nsdispatch.c,v 1.22 2004/07/24 18:42:51 thorpej 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.22   thorpej __RCSID("$NetBSD: nsdispatch.c,v 1.22 2004/07/24 18:42:51 thorpej 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.2     lukem 
     82  1.12     lukem #include <assert.h>
     83  1.22   thorpej #ifdef __ELF__
     84  1.22   thorpej #include <dlfcn.h>
     85  1.22   thorpej #endif /* __ELF__ */
     86   1.2     lukem #include <err.h>
     87   1.2     lukem #include <fcntl.h>
     88   1.2     lukem #define _NS_PRIVATE
     89   1.2     lukem #include <nsswitch.h>
     90  1.18       wiz #include <stdarg.h>
     91   1.2     lukem #include <stdio.h>
     92   1.2     lukem #include <stdlib.h>
     93   1.2     lukem #include <string.h>
     94   1.2     lukem #include <unistd.h>
     95  1.22   thorpej 
     96  1.22   thorpej #include "reentrant.h"
     97  1.10     lukem 
     98  1.17  christos extern	FILE 	*_nsyyin;
     99  1.21   thorpej extern	int	 _nsyyparse(void);
    100  1.17  christos 
    101  1.17  christos 
    102   1.6     lukem #ifdef __weak_alias
    103  1.16   mycroft __weak_alias(nsdispatch,_nsdispatch)
    104   1.6     lukem #endif
    105   1.2     lukem 
    106   1.2     lukem 
    107   1.5     lukem /*
    108   1.5     lukem  * default sourcelist: `files'
    109   1.5     lukem  */
    110   1.5     lukem const ns_src __nsdefaultsrc[] = {
    111   1.5     lukem 	{ NSSRC_FILES, NS_SUCCESS },
    112   1.5     lukem 	{ 0 },
    113   1.5     lukem };
    114   1.5     lukem 
    115  1.22   thorpej /* Database, source mappings. */
    116  1.22   thorpej static	u_int			 _nsmapsize;
    117  1.22   thorpej static	ns_dbt			*_nsmap;
    118  1.22   thorpej 
    119  1.22   thorpej /* Nsswitch modules. */
    120  1.22   thorpej static	u_int			 _nsmodsize;
    121  1.22   thorpej static	ns_mod			*_nsmod;
    122  1.22   thorpej 
    123  1.22   thorpej /* Placeholder for built-in modules' dlopen() handles. */
    124  1.22   thorpej static	void			*_nsbuiltin = &_nsbuiltin;
    125   1.5     lukem 
    126  1.19  christos #ifdef _REENTRANT
    127  1.22   thorpej /*
    128  1.22   thorpej  * Global nsswitch data structures are mostly read-only, but we update them
    129  1.22   thorpej  * when we read or re-read nsswitch.conf.
    130  1.22   thorpej  */
    131  1.22   thorpej static 	rwlock_t		_nslock = RWLOCK_INITIALIZER;
    132  1.22   thorpej #endif
    133  1.22   thorpej 
    134  1.22   thorpej 
    135  1.22   thorpej /*
    136  1.22   thorpej  * Runtime determination of whether we are dynamically linked or not.
    137  1.22   thorpej  */
    138  1.22   thorpej #ifdef __ELF__
    139  1.22   thorpej extern	int			_DYNAMIC __attribute__((__weak__));
    140  1.22   thorpej #define	is_dynamic()		(&_DYNAMIC != NULL)
    141  1.19  christos #else
    142  1.22   thorpej #define	is_dynamic()		(0)	/* don't bother - switch to ELF! */
    143  1.22   thorpej #endif /* __ELF__ */
    144  1.19  christos 
    145   1.2     lukem 
    146   1.2     lukem /*
    147  1.22   thorpej  * size of dynamic array chunk for _nsmap and _nsmap[x].srclist (and other
    148  1.22   thorpej  * growing arrays).
    149   1.2     lukem  */
    150   1.2     lukem #define NSELEMSPERCHUNK		8
    151   1.2     lukem 
    152  1.22   thorpej /*
    153  1.22   thorpej  * Dynamically growable arrays are used for lists of databases, sources,
    154  1.22   thorpej  * and modules.  The following "vector" API is used to isolate the
    155  1.22   thorpej  * common operations.
    156  1.22   thorpej  */
    157  1.22   thorpej typedef void	(*_nsvect_free_elem)(void *);
    158  1.22   thorpej 
    159  1.22   thorpej static void *
    160  1.22   thorpej _nsvect_append(const void *elem, void *vec, u_int *count, size_t esize)
    161  1.22   thorpej {
    162  1.22   thorpej 	void	*p;
    163  1.22   thorpej 
    164  1.22   thorpej 	if ((*count % NSELEMSPERCHUNK) == 0) {
    165  1.22   thorpej 		p = realloc(vec, (*count + NSELEMSPERCHUNK) * esize);
    166  1.22   thorpej 		if (p == NULL)
    167  1.22   thorpej 			return (NULL);
    168  1.22   thorpej 		vec = p;
    169  1.22   thorpej 	}
    170  1.22   thorpej 	memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize);
    171  1.22   thorpej 	(*count)++;
    172  1.22   thorpej 	return (vec);
    173  1.22   thorpej }
    174  1.22   thorpej 
    175  1.22   thorpej static void *
    176  1.22   thorpej _nsvect_elem(u_int i, void *vec, u_int count, size_t esize)
    177  1.22   thorpej {
    178  1.22   thorpej 
    179  1.22   thorpej 	if (i < count)
    180  1.22   thorpej 		return ((void *)((uintptr_t)vec + (i * esize)));
    181  1.22   thorpej 	else
    182  1.22   thorpej 		return (NULL);
    183  1.22   thorpej }
    184  1.22   thorpej 
    185  1.22   thorpej static void
    186  1.22   thorpej _nsvect_free(void *vec, u_int *count, size_t esize, _nsvect_free_elem free_elem)
    187  1.22   thorpej {
    188  1.22   thorpej 	void	*elem;
    189  1.22   thorpej 	u_int	 i;
    190  1.22   thorpej 
    191  1.22   thorpej 	for (i = 0; i < *count; i++) {
    192  1.22   thorpej 		elem = _nsvect_elem(i, vec, *count, esize);
    193  1.22   thorpej 		if (elem != NULL)
    194  1.22   thorpej 			(*free_elem)(elem);
    195  1.22   thorpej 	}
    196  1.22   thorpej 	if (vec != NULL)
    197  1.22   thorpej 		free(vec);
    198  1.22   thorpej 	*count = 0;
    199  1.22   thorpej }
    200  1.22   thorpej #define	_NSVECT_FREE(v, c, s, f)					\
    201  1.22   thorpej do {									\
    202  1.22   thorpej 	_nsvect_free((v), (c), (s), (f));				\
    203  1.22   thorpej 	(v) = NULL;							\
    204  1.22   thorpej } while (/*CONSTCOND*/0)
    205   1.2     lukem 
    206  1.21   thorpej static int
    207  1.22   thorpej _nsdbtcmp(const void *a, const void *b)
    208   1.2     lukem {
    209  1.22   thorpej 
    210   1.7  christos 	return (strcasecmp(((const ns_dbt *)a)->name,
    211   1.7  christos 	    ((const ns_dbt *)b)->name));
    212   1.2     lukem }
    213   1.2     lukem 
    214  1.22   thorpej static int
    215  1.22   thorpej _nsmodcmp(const void *a, const void *b)
    216  1.22   thorpej {
    217  1.22   thorpej 
    218  1.22   thorpej 	return (strcasecmp(((const ns_mod *)a)->name,
    219  1.22   thorpej 	    ((const ns_mod *)b)->name));
    220  1.22   thorpej }
    221  1.22   thorpej 
    222  1.22   thorpej static int
    223  1.22   thorpej _nsmtabcmp(const void *a, const void *b)
    224  1.22   thorpej {
    225  1.22   thorpej 	int	cmp;
    226  1.22   thorpej 
    227  1.22   thorpej 	cmp = strcmp(((const ns_mtab *)a)->name,
    228  1.22   thorpej 	    ((const ns_mtab *)b)->name);
    229  1.22   thorpej 	if (cmp)
    230  1.22   thorpej 		return (cmp);
    231  1.22   thorpej 
    232  1.22   thorpej 	return (strcasecmp(((const ns_mtab *)a)->database,
    233  1.22   thorpej 	    ((const ns_mtab *)b)->database));
    234  1.22   thorpej }
    235  1.22   thorpej 
    236  1.22   thorpej static void
    237  1.22   thorpej _nsmodfree(ns_mod *mod)
    238  1.22   thorpej {
    239  1.22   thorpej 
    240  1.22   thorpej 	/*LINTED const cast*/
    241  1.22   thorpej 	free((void *)mod->name);
    242  1.22   thorpej 	if (mod->handle == NULL)
    243  1.22   thorpej 		return;
    244  1.22   thorpej 	if (mod->unregister != NULL)
    245  1.22   thorpej 		(*mod->unregister)(mod->mtab, mod->mtabsize);
    246  1.22   thorpej #ifdef __ELF__
    247  1.22   thorpej 	if (mod->handle != _nsbuiltin)
    248  1.22   thorpej 		(void) dlclose(mod->handle);
    249  1.22   thorpej #endif /* __ELF__ */
    250  1.22   thorpej }
    251  1.22   thorpej 
    252  1.22   thorpej /*
    253  1.22   thorpej  * Load a built-in or dyanamically linked module.  If the `reg_fn'
    254  1.22   thorpej  * argument is non-NULL, assume a built-in module and use `reg_fn'
    255  1.22   thorpej  * to register it.  Otherwise, search for a dynamic nsswitch module.
    256  1.22   thorpej  */
    257  1.22   thorpej static int
    258  1.22   thorpej _nsloadmod(const char *source, nss_module_register_fn reg_fn)
    259  1.22   thorpej {
    260  1.22   thorpej 	char	buf[PATH_MAX];
    261  1.22   thorpej 	ns_mod	mod, *new;
    262  1.22   thorpej 
    263  1.22   thorpej 	memset(&mod, 0, sizeof(mod));
    264  1.22   thorpej 	mod.name = strdup(source);
    265  1.22   thorpej 	if (mod.name == NULL)
    266  1.22   thorpej 		return (-1);
    267  1.22   thorpej 
    268  1.22   thorpej 	if (reg_fn != NULL) {
    269  1.22   thorpej 		/*
    270  1.22   thorpej 		 * The placeholder is required, as a NULL handle
    271  1.22   thorpej 		 * represents an invalid module.
    272  1.22   thorpej 		 */
    273  1.22   thorpej 		mod.handle = _nsbuiltin;
    274  1.22   thorpej 	} else if (!is_dynamic()) {
    275  1.22   thorpej 		goto out;
    276  1.22   thorpej 	} else {
    277  1.22   thorpej #ifdef __ELF__
    278  1.22   thorpej 		if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
    279  1.22   thorpej 		    NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
    280  1.22   thorpej 			goto out;
    281  1.22   thorpej 		mod.handle = dlopen(buf, RTLD_LOCAL | RTLD_LAZY);
    282  1.22   thorpej 		if (mod.handle == NULL) {
    283  1.22   thorpej #ifdef _NSS_DEBUG
    284  1.22   thorpej 			/*
    285  1.22   thorpej 			 * This gets pretty annoying, since the built-in
    286  1.22   thorpej 			 * sources are not yet modules.
    287  1.22   thorpej 			 */
    288  1.22   thorpej 			/* XXX log some error? */
    289  1.22   thorpej #endif
    290  1.22   thorpej 			goto out;
    291  1.22   thorpej 		}
    292  1.22   thorpej 		reg_fn = (nss_module_register_fn) dlsym(mod.handle,
    293  1.22   thorpej 		    "nss_module_register");
    294  1.22   thorpej 		if (reg_fn == NULL) {
    295  1.22   thorpej 			(void) dlclose(mod.handle);
    296  1.22   thorpej 			mod.handle = NULL;
    297  1.22   thorpej 			/* XXX log some error? */
    298  1.22   thorpej 			goto out;
    299  1.22   thorpej 		}
    300  1.22   thorpej #else /* ! __ELF__ */
    301  1.22   thorpej 		mod.handle = NULL;
    302  1.22   thorpej #endif /* __ELF__ */
    303  1.22   thorpej 	}
    304  1.22   thorpej 	mod.mtab = (*reg_fn)(mod.name, &mod.mtabsize, &mod.unregister);
    305  1.22   thorpej 	if (mod.mtab == NULL || mod.mtabsize == 0) {
    306  1.22   thorpej #ifdef __ELF__
    307  1.22   thorpej 		if (mod.handle != _nsbuiltin)
    308  1.22   thorpej 			(void) dlclose(mod.handle);
    309  1.22   thorpej #endif /* __ELF__ */
    310  1.22   thorpej 		mod.handle = NULL;
    311  1.22   thorpej 		/* XXX log some error? */
    312  1.22   thorpej 		goto out;
    313  1.22   thorpej 	}
    314  1.22   thorpej 	if (mod.mtabsize > 1)
    315  1.22   thorpej 		qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
    316  1.22   thorpej 		    _nsmtabcmp);
    317  1.22   thorpej  out:
    318  1.22   thorpej 	new = _nsvect_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod));
    319  1.22   thorpej 	if (new == NULL) {
    320  1.22   thorpej 		_nsmodfree(&mod);
    321  1.22   thorpej 		return (-1);
    322  1.22   thorpej 	}
    323  1.22   thorpej 	_nsmod = new;
    324  1.22   thorpej 	/* _nsmodsize already incremented */
    325  1.22   thorpej 
    326  1.22   thorpej 	qsort(_nsmod, _nsmodsize, sizeof(*_nsmod), _nsmodcmp);
    327  1.22   thorpej 	return (0);
    328  1.22   thorpej }
    329  1.22   thorpej 
    330  1.22   thorpej static void
    331  1.22   thorpej _nsloadbuiltin(void)
    332  1.22   thorpej {
    333  1.22   thorpej 
    334  1.22   thorpej 	/* Do nothing, for now. */
    335  1.22   thorpej }
    336   1.2     lukem 
    337  1.15     lukem int
    338  1.21   thorpej _nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
    339   1.2     lukem {
    340  1.22   thorpej 	void		*new;
    341  1.22   thorpej 	const ns_mod	*mod;
    342  1.22   thorpej 	ns_mod		 modkey;
    343  1.12     lukem 
    344  1.12     lukem 	_DIAGASSERT(dbt != NULL);
    345  1.12     lukem 	_DIAGASSERT(src != NULL);
    346  1.12     lukem 
    347  1.22   thorpej 	new = _nsvect_append(src, dbt->srclist, &dbt->srclistsize,
    348  1.22   thorpej 	    sizeof(*src));
    349  1.22   thorpej 	if (new == NULL)
    350  1.22   thorpej 		return (-1);
    351  1.22   thorpej 	dbt->srclist = new;
    352  1.22   thorpej 	/* dbt->srclistsize already incremented */
    353  1.22   thorpej 
    354  1.22   thorpej 	modkey.name = src->name;
    355  1.22   thorpej 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod),
    356  1.22   thorpej 	    _nsmodcmp);
    357  1.22   thorpej 	if (mod == NULL)
    358  1.22   thorpej 		return (_nsloadmod(src->name, NULL));
    359  1.15     lukem 
    360  1.15     lukem 	return (0);
    361   1.2     lukem }
    362   1.2     lukem 
    363   1.2     lukem void
    364  1.21   thorpej _nsdbtdump(const ns_dbt *dbt)
    365   1.2     lukem {
    366  1.22   thorpej 	int	i;
    367   1.2     lukem 
    368  1.12     lukem 	_DIAGASSERT(dbt != NULL);
    369  1.12     lukem 
    370   1.2     lukem 	printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
    371   1.2     lukem 	    dbt->srclistsize == 1 ? "" : "s");
    372   1.2     lukem 	for (i = 0; i < dbt->srclistsize; i++) {
    373   1.2     lukem 		printf(" %s", dbt->srclist[i].name);
    374   1.2     lukem 		if (!(dbt->srclist[i].flags &
    375   1.2     lukem 		    (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
    376   1.2     lukem 		    (dbt->srclist[i].flags & NS_SUCCESS))
    377   1.2     lukem 			continue;
    378   1.2     lukem 		printf(" [");
    379   1.2     lukem 		if (!(dbt->srclist[i].flags & NS_SUCCESS))
    380   1.2     lukem 			printf(" SUCCESS=continue");
    381   1.2     lukem 		if (dbt->srclist[i].flags & NS_UNAVAIL)
    382   1.2     lukem 			printf(" UNAVAIL=return");
    383   1.2     lukem 		if (dbt->srclist[i].flags & NS_NOTFOUND)
    384   1.2     lukem 			printf(" NOTFOUND=return");
    385   1.2     lukem 		if (dbt->srclist[i].flags & NS_TRYAGAIN)
    386   1.2     lukem 			printf(" TRYAGAIN=return");
    387   1.2     lukem 		printf(" ]");
    388   1.2     lukem 	}
    389   1.2     lukem 	printf("\n");
    390   1.2     lukem }
    391   1.2     lukem 
    392  1.22   thorpej static void
    393  1.22   thorpej _nssrclist_free(ns_src **src, u_int srclistsize)
    394   1.2     lukem {
    395  1.22   thorpej 	u_int	i;
    396   1.2     lukem 
    397  1.22   thorpej 	for (i = 0; i < srclistsize; i++) {
    398  1.22   thorpej 		if ((*src)[i].name != NULL) {
    399  1.22   thorpej 			/*LINTED const cast*/
    400  1.22   thorpej 			free((void *)(*src)[i].name);
    401  1.22   thorpej 		}
    402  1.22   thorpej 	}
    403  1.22   thorpej 	free(*src);
    404  1.22   thorpej 	*src = NULL;
    405  1.22   thorpej }
    406   1.2     lukem 
    407  1.22   thorpej static void
    408  1.22   thorpej _nsdbtfree(ns_dbt *dbt)
    409  1.22   thorpej {
    410   1.2     lukem 
    411  1.22   thorpej 	_nssrclist_free(&dbt->srclist, dbt->srclistsize);
    412  1.22   thorpej 	if (dbt->name != NULL) {
    413  1.22   thorpej 		/*LINTED const cast*/
    414  1.22   thorpej 		free((void *)dbt->name);
    415   1.2     lukem 	}
    416   1.2     lukem }
    417   1.2     lukem 
    418  1.15     lukem int
    419  1.21   thorpej _nsdbtput(const ns_dbt *dbt)
    420   1.2     lukem {
    421  1.22   thorpej 	ns_dbt	*p;
    422  1.22   thorpej 	void	*new;
    423  1.22   thorpej 	u_int	i;
    424   1.2     lukem 
    425  1.12     lukem 	_DIAGASSERT(dbt != NULL);
    426  1.12     lukem 
    427   1.2     lukem 	for (i = 0; i < _nsmapsize; i++) {
    428  1.22   thorpej 		p = _nsvect_elem(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
    429  1.22   thorpej 		if (strcasecmp(dbt->name, p->name) == 0) {
    430   1.2     lukem 					/* overwrite existing entry */
    431  1.22   thorpej 			if (p->srclist != NULL)
    432  1.22   thorpej 				_nssrclist_free(&p->srclist, p->srclistsize);
    433  1.22   thorpej 			memmove(p, dbt, sizeof(*dbt));
    434  1.15     lukem 			return (0);
    435   1.2     lukem 		}
    436   1.2     lukem 	}
    437  1.22   thorpej 	new = _nsvect_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap));
    438  1.22   thorpej 	if (new == NULL)
    439  1.22   thorpej 		return (-1);
    440  1.22   thorpej 	_nsmap = new;
    441  1.22   thorpej 	/* _nsmapsize already incremented */
    442   1.2     lukem 
    443  1.22   thorpej 	return (0);
    444  1.22   thorpej }
    445  1.22   thorpej 
    446  1.22   thorpej /*
    447  1.22   thorpej  * This function is called each time nsdispatch() is called.  If this
    448  1.22   thorpej  * is the first call, or if the configuration has changed, (re-)prepare
    449  1.22   thorpej  * the global data used by NSS.
    450  1.22   thorpej  */
    451  1.22   thorpej static int
    452  1.22   thorpej _nsconfigure(void)
    453  1.22   thorpej {
    454  1.22   thorpej #ifdef _REENTRANT
    455  1.22   thorpej 	static mutex_t	_nsconflock = MUTEX_INITIALIZER;
    456  1.22   thorpej #endif
    457  1.22   thorpej 	static time_t	_nsconfmod;
    458  1.22   thorpej 	struct stat	statbuf;
    459  1.15     lukem 
    460  1.22   thorpej 	mutex_lock(&_nsconflock);
    461  1.22   thorpej 
    462  1.22   thorpej 	if (stat(_PATH_NS_CONF, &statbuf) == -1) {
    463  1.22   thorpej 		/*
    464  1.22   thorpej 		 * No nsswitch.conf; just use whatever configuration we
    465  1.22   thorpej 		 * currently have, or fall back on the defaults specified
    466  1.22   thorpej 		 * by the caller.
    467  1.22   thorpej 		 */
    468  1.22   thorpej 		mutex_unlock(&_nsconflock);
    469  1.22   thorpej 		return (0);
    470  1.22   thorpej 	}
    471  1.22   thorpej 
    472  1.22   thorpej 	if (statbuf.st_mtime <= _nsconfmod) {
    473  1.22   thorpej 		/* Internal state is up-to-date with nsswitch.conf. */
    474  1.22   thorpej 		mutex_unlock(&_nsconflock);
    475  1.22   thorpej 		return (0);
    476  1.22   thorpej 	}
    477  1.22   thorpej 
    478  1.22   thorpej 	/*
    479  1.22   thorpej 	 * Ok, we've decided we need to update the nsswitch configuration
    480  1.22   thorpej 	 * structures.  Update the timestamp, acquire a write-lock on
    481  1.22   thorpej 	 * _nslock, and then release _nsconflock.  This means that we don't
    482  1.22   thorpej 	 * need to acquire _nsconflock again to update the timetamp, and
    483  1.22   thorpej 	 * prevents another thread from updating the configuration before
    484  1.22   thorpej 	 * we're finished, even if they decide that they need to.
    485  1.22   thorpej 	 *
    486  1.22   thorpej 	 * Acquiring the locks in this fashion is safe: Only here are
    487  1.22   thorpej 	 * both _nslock and _nsconflock both taken, and nsdispatch()
    488  1.22   thorpej 	 * should never be called recursively.
    489  1.22   thorpej 	 */
    490  1.22   thorpej 
    491  1.22   thorpej 	_nsconfmod = statbuf.st_mtime;
    492  1.22   thorpej 	rwlock_wrlock(&_nslock);
    493  1.22   thorpej 	mutex_unlock(&_nsconflock);
    494  1.22   thorpej 
    495  1.22   thorpej 	_nsyyin = fopen(_PATH_NS_CONF, "r");
    496  1.22   thorpej 	if (_nsyyin == NULL) {
    497  1.22   thorpej 		/*
    498  1.22   thorpej 		 * Unable to open nsswitch.conf; behave as though the
    499  1.22   thorpej 		 * stat() above failed.  Even though we have already
    500  1.22   thorpej 		 * updated _nsconfmod, if the file reappears, the
    501  1.22   thorpej 		 * mtime will change.
    502  1.22   thorpej 		 */
    503  1.22   thorpej 		rwlock_unlock(&_nslock);
    504  1.22   thorpej 		return (0);
    505   1.2     lukem 	}
    506  1.22   thorpej 
    507  1.22   thorpej 	_NSVECT_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
    508  1.22   thorpej 	    (_nsvect_free_elem) _nsdbtfree);
    509  1.22   thorpej 	_NSVECT_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
    510  1.22   thorpej 	    (_nsvect_free_elem) _nsmodfree);
    511  1.22   thorpej 
    512  1.22   thorpej 	_nsloadbuiltin();
    513  1.22   thorpej 
    514  1.22   thorpej 	_nsyyparse();
    515  1.22   thorpej 	(void) fclose(_nsyyin);
    516  1.22   thorpej 	if (_nsmapsize != 0)
    517  1.22   thorpej 		qsort(_nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    518  1.22   thorpej 	rwlock_unlock(&_nslock);
    519  1.22   thorpej 
    520  1.15     lukem 	return (0);
    521   1.2     lukem }
    522   1.2     lukem 
    523  1.22   thorpej static nss_method
    524  1.22   thorpej _nsmethod(const char *source, const char *database, const char *method,
    525  1.22   thorpej     const ns_dtab disp_tab[], void **cb_data)
    526  1.22   thorpej {
    527  1.22   thorpej 	int	curdisp;
    528  1.22   thorpej 	ns_mod	*mod, modkey;
    529  1.22   thorpej 	ns_mtab	*mtab, mtabkey;
    530  1.22   thorpej 
    531  1.22   thorpej 	if (disp_tab != NULL) {
    532  1.22   thorpej 		for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) {
    533  1.22   thorpej 			if (strcasecmp(source, disp_tab[curdisp].src) == 0) {
    534  1.22   thorpej 				*cb_data = disp_tab[curdisp].cb_data;
    535  1.22   thorpej 				return (disp_tab[curdisp].callback);
    536  1.22   thorpej 			}
    537  1.22   thorpej 		}
    538  1.22   thorpej 	}
    539  1.22   thorpej 
    540  1.22   thorpej 	modkey.name = source;
    541  1.22   thorpej 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod),
    542  1.22   thorpej 	    _nsmodcmp);
    543  1.22   thorpej 	if (mod != NULL && mod->handle != NULL) {
    544  1.22   thorpej 		mtabkey.database = database;
    545  1.22   thorpej 		mtabkey.name = method;
    546  1.22   thorpej 		mtab = bsearch(&mtabkey, mod->mtab, mod->mtabsize,
    547  1.22   thorpej 		    sizeof(mod->mtab[0]), _nsmtabcmp);
    548  1.22   thorpej 		if (mtab != NULL) {
    549  1.22   thorpej 			*cb_data = mtab->mdata;
    550  1.22   thorpej 			return (mtab->method);
    551  1.22   thorpej 		}
    552  1.22   thorpej 	}
    553  1.22   thorpej 
    554  1.22   thorpej 	*cb_data = NULL;
    555  1.22   thorpej 	return (NULL);
    556  1.22   thorpej }
    557   1.2     lukem 
    558   1.2     lukem int
    559  1.11  christos /*ARGSUSED*/
    560   1.5     lukem nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
    561   1.5     lukem 	    const char *method, const ns_src defaults[], ...)
    562   1.2     lukem {
    563   1.2     lukem 	va_list		 ap;
    564  1.22   thorpej 	int		 i, result;
    565  1.22   thorpej 	ns_dbt		 key;
    566   1.2     lukem 	const ns_dbt	*dbt;
    567   1.5     lukem 	const ns_src	*srclist;
    568   1.5     lukem 	int		 srclistsize;
    569  1.22   thorpej 	nss_method	 cb;
    570  1.22   thorpej 	void		*cb_data;
    571  1.12     lukem 
    572  1.12     lukem 	_DIAGASSERT(database != NULL);
    573  1.12     lukem 	_DIAGASSERT(method != NULL);
    574  1.12     lukem 	if (database == NULL || method == NULL)
    575  1.12     lukem 		return (NS_UNAVAIL);
    576   1.2     lukem 
    577  1.22   thorpej 	if (_nsconfigure())
    578  1.22   thorpej 		return (NS_UNAVAIL);
    579  1.22   thorpej 
    580  1.22   thorpej 	rwlock_rdlock(&_nslock);
    581  1.22   thorpej 
    582  1.22   thorpej 	key.name = database;
    583  1.22   thorpej 	dbt = bsearch(&key, _nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    584   1.5     lukem 	if (dbt != NULL) {
    585   1.5     lukem 		srclist = dbt->srclist;
    586   1.5     lukem 		srclistsize = dbt->srclistsize;
    587   1.5     lukem 	} else {
    588   1.5     lukem 		srclist = defaults;
    589   1.5     lukem 		srclistsize = 0;
    590   1.5     lukem 		while (srclist[srclistsize].name != NULL)
    591   1.5     lukem 			srclistsize++;
    592   1.5     lukem 	}
    593   1.2     lukem 	result = 0;
    594   1.2     lukem 
    595   1.5     lukem 	for (i = 0; i < srclistsize; i++) {
    596  1.22   thorpej 		cb = _nsmethod(srclist[i].name, database, method,
    597  1.22   thorpej 		    disp_tab, &cb_data);
    598   1.2     lukem 		result = 0;
    599  1.22   thorpej 		if (cb != NULL) {
    600   1.5     lukem 			va_start(ap, defaults);
    601  1.22   thorpej 			result = (*cb)(retval, cb_data, ap);
    602   1.2     lukem 			va_end(ap);
    603  1.22   thorpej 			if (result & srclist[i].flags)
    604   1.2     lukem 				break;
    605   1.2     lukem 		}
    606   1.2     lukem 	}
    607  1.22   thorpej 
    608  1.22   thorpej 	rwlock_unlock(&_nslock);
    609  1.22   thorpej 
    610   1.2     lukem 	return (result ? result : NS_NOTFOUND);
    611   1.2     lukem }
    612