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