Home | History | Annotate | Line # | Download | only in net
nsdispatch.c revision 1.28.2.1
      1  1.28.2.1      tron /*	$NetBSD: nsdispatch.c,v 1.28.2.1 2005/07/02 23:21:24 tron 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.28.2.1      tron __RCSID("$NetBSD: nsdispatch.c,v 1.28.2.1 2005/07/02 23:21:24 tron 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.22   thorpej 	/*LINTED const cast*/
    285      1.22   thorpej 	free((void *)mod->name);
    286      1.22   thorpej 	if (mod->handle == NULL)
    287      1.22   thorpej 		return;
    288      1.22   thorpej 	if (mod->unregister != NULL)
    289      1.22   thorpej 		(*mod->unregister)(mod->mtab, mod->mtabsize);
    290      1.22   thorpej #ifdef __ELF__
    291      1.22   thorpej 	if (mod->handle != _nsbuiltin)
    292      1.22   thorpej 		(void) dlclose(mod->handle);
    293      1.22   thorpej #endif /* __ELF__ */
    294      1.22   thorpej }
    295      1.22   thorpej 
    296      1.22   thorpej /*
    297      1.22   thorpej  * Load a built-in or dyanamically linked module.  If the `reg_fn'
    298      1.22   thorpej  * argument is non-NULL, assume a built-in module and use `reg_fn'
    299      1.22   thorpej  * to register it.  Otherwise, search for a dynamic nsswitch module.
    300      1.22   thorpej  */
    301      1.22   thorpej static int
    302      1.22   thorpej _nsloadmod(const char *source, nss_module_register_fn reg_fn)
    303      1.22   thorpej {
    304      1.24    simonb #ifdef __ELF__
    305      1.22   thorpej 	char	buf[PATH_MAX];
    306      1.24    simonb #endif
    307      1.22   thorpej 	ns_mod	mod, *new;
    308      1.22   thorpej 
    309      1.22   thorpej 	memset(&mod, 0, sizeof(mod));
    310      1.22   thorpej 	mod.name = strdup(source);
    311      1.22   thorpej 	if (mod.name == NULL)
    312      1.22   thorpej 		return (-1);
    313      1.22   thorpej 
    314      1.22   thorpej 	if (reg_fn != NULL) {
    315      1.22   thorpej 		/*
    316      1.22   thorpej 		 * The placeholder is required, as a NULL handle
    317      1.22   thorpej 		 * represents an invalid module.
    318      1.22   thorpej 		 */
    319      1.22   thorpej 		mod.handle = _nsbuiltin;
    320      1.22   thorpej 	} else if (!is_dynamic()) {
    321      1.22   thorpej 		goto out;
    322      1.22   thorpej 	} else {
    323      1.22   thorpej #ifdef __ELF__
    324      1.22   thorpej 		if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
    325      1.22   thorpej 		    NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
    326      1.22   thorpej 			goto out;
    327      1.22   thorpej 		mod.handle = dlopen(buf, RTLD_LOCAL | RTLD_LAZY);
    328      1.22   thorpej 		if (mod.handle == NULL) {
    329      1.22   thorpej #ifdef _NSS_DEBUG
    330      1.22   thorpej 			/*
    331      1.22   thorpej 			 * This gets pretty annoying, since the built-in
    332      1.22   thorpej 			 * sources are not yet modules.
    333      1.22   thorpej 			 */
    334      1.22   thorpej 			/* XXX log some error? */
    335      1.22   thorpej #endif
    336      1.22   thorpej 			goto out;
    337      1.22   thorpej 		}
    338      1.22   thorpej 		reg_fn = (nss_module_register_fn) dlsym(mod.handle,
    339      1.22   thorpej 		    "nss_module_register");
    340      1.22   thorpej 		if (reg_fn == NULL) {
    341      1.22   thorpej 			(void) dlclose(mod.handle);
    342      1.22   thorpej 			mod.handle = NULL;
    343      1.22   thorpej 			/* XXX log some error? */
    344      1.22   thorpej 			goto out;
    345      1.22   thorpej 		}
    346      1.22   thorpej #else /* ! __ELF__ */
    347      1.22   thorpej 		mod.handle = NULL;
    348      1.22   thorpej #endif /* __ELF__ */
    349      1.22   thorpej 	}
    350      1.22   thorpej 	mod.mtab = (*reg_fn)(mod.name, &mod.mtabsize, &mod.unregister);
    351      1.22   thorpej 	if (mod.mtab == NULL || mod.mtabsize == 0) {
    352      1.22   thorpej #ifdef __ELF__
    353      1.22   thorpej 		if (mod.handle != _nsbuiltin)
    354      1.22   thorpej 			(void) dlclose(mod.handle);
    355      1.22   thorpej #endif /* __ELF__ */
    356      1.22   thorpej 		mod.handle = NULL;
    357      1.22   thorpej 		/* XXX log some error? */
    358      1.22   thorpej 		goto out;
    359      1.22   thorpej 	}
    360      1.22   thorpej 	if (mod.mtabsize > 1)
    361      1.22   thorpej 		qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
    362      1.22   thorpej 		    _nsmtabcmp);
    363      1.22   thorpej  out:
    364      1.22   thorpej 	new = _nsvect_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod));
    365      1.22   thorpej 	if (new == NULL) {
    366      1.22   thorpej 		_nsmodfree(&mod);
    367      1.22   thorpej 		return (-1);
    368      1.22   thorpej 	}
    369      1.22   thorpej 	_nsmod = new;
    370      1.22   thorpej 	/* _nsmodsize already incremented */
    371      1.22   thorpej 
    372      1.22   thorpej 	qsort(_nsmod, _nsmodsize, sizeof(*_nsmod), _nsmodcmp);
    373      1.22   thorpej 	return (0);
    374      1.22   thorpej }
    375      1.22   thorpej 
    376      1.22   thorpej static void
    377      1.22   thorpej _nsloadbuiltin(void)
    378      1.22   thorpej {
    379      1.22   thorpej 
    380      1.22   thorpej 	/* Do nothing, for now. */
    381      1.22   thorpej }
    382       1.2     lukem 
    383      1.15     lukem int
    384      1.21   thorpej _nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
    385       1.2     lukem {
    386      1.22   thorpej 	void		*new;
    387      1.22   thorpej 	const ns_mod	*mod;
    388      1.22   thorpej 	ns_mod		 modkey;
    389      1.12     lukem 
    390      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    391      1.12     lukem 	_DIAGASSERT(src != NULL);
    392      1.12     lukem 
    393      1.22   thorpej 	new = _nsvect_append(src, dbt->srclist, &dbt->srclistsize,
    394      1.22   thorpej 	    sizeof(*src));
    395      1.22   thorpej 	if (new == NULL)
    396      1.22   thorpej 		return (-1);
    397      1.22   thorpej 	dbt->srclist = new;
    398      1.22   thorpej 	/* dbt->srclistsize already incremented */
    399      1.22   thorpej 
    400      1.22   thorpej 	modkey.name = src->name;
    401      1.22   thorpej 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod),
    402      1.22   thorpej 	    _nsmodcmp);
    403      1.22   thorpej 	if (mod == NULL)
    404      1.22   thorpej 		return (_nsloadmod(src->name, NULL));
    405      1.15     lukem 
    406      1.15     lukem 	return (0);
    407       1.2     lukem }
    408       1.2     lukem 
    409       1.2     lukem void
    410      1.21   thorpej _nsdbtdump(const ns_dbt *dbt)
    411       1.2     lukem {
    412      1.22   thorpej 	int	i;
    413       1.2     lukem 
    414      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    415      1.12     lukem 
    416       1.2     lukem 	printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
    417       1.2     lukem 	    dbt->srclistsize == 1 ? "" : "s");
    418       1.2     lukem 	for (i = 0; i < dbt->srclistsize; i++) {
    419       1.2     lukem 		printf(" %s", dbt->srclist[i].name);
    420       1.2     lukem 		if (!(dbt->srclist[i].flags &
    421       1.2     lukem 		    (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
    422       1.2     lukem 		    (dbt->srclist[i].flags & NS_SUCCESS))
    423       1.2     lukem 			continue;
    424       1.2     lukem 		printf(" [");
    425       1.2     lukem 		if (!(dbt->srclist[i].flags & NS_SUCCESS))
    426       1.2     lukem 			printf(" SUCCESS=continue");
    427       1.2     lukem 		if (dbt->srclist[i].flags & NS_UNAVAIL)
    428       1.2     lukem 			printf(" UNAVAIL=return");
    429       1.2     lukem 		if (dbt->srclist[i].flags & NS_NOTFOUND)
    430       1.2     lukem 			printf(" NOTFOUND=return");
    431       1.2     lukem 		if (dbt->srclist[i].flags & NS_TRYAGAIN)
    432       1.2     lukem 			printf(" TRYAGAIN=return");
    433       1.2     lukem 		printf(" ]");
    434       1.2     lukem 	}
    435       1.2     lukem 	printf("\n");
    436       1.2     lukem }
    437       1.2     lukem 
    438      1.22   thorpej static void
    439      1.22   thorpej _nssrclist_free(ns_src **src, u_int srclistsize)
    440       1.2     lukem {
    441      1.22   thorpej 	u_int	i;
    442       1.2     lukem 
    443      1.22   thorpej 	for (i = 0; i < srclistsize; i++) {
    444      1.22   thorpej 		if ((*src)[i].name != NULL) {
    445      1.22   thorpej 			/*LINTED const cast*/
    446      1.22   thorpej 			free((void *)(*src)[i].name);
    447      1.22   thorpej 		}
    448      1.22   thorpej 	}
    449      1.22   thorpej 	free(*src);
    450      1.22   thorpej 	*src = NULL;
    451      1.22   thorpej }
    452       1.2     lukem 
    453      1.22   thorpej static void
    454      1.22   thorpej _nsdbtfree(ns_dbt *dbt)
    455      1.22   thorpej {
    456       1.2     lukem 
    457      1.22   thorpej 	_nssrclist_free(&dbt->srclist, dbt->srclistsize);
    458      1.22   thorpej 	if (dbt->name != NULL) {
    459      1.22   thorpej 		/*LINTED const cast*/
    460      1.22   thorpej 		free((void *)dbt->name);
    461       1.2     lukem 	}
    462       1.2     lukem }
    463       1.2     lukem 
    464      1.15     lukem int
    465      1.21   thorpej _nsdbtput(const ns_dbt *dbt)
    466       1.2     lukem {
    467      1.22   thorpej 	ns_dbt	*p;
    468      1.22   thorpej 	void	*new;
    469      1.22   thorpej 	u_int	i;
    470       1.2     lukem 
    471      1.12     lukem 	_DIAGASSERT(dbt != NULL);
    472      1.12     lukem 
    473       1.2     lukem 	for (i = 0; i < _nsmapsize; i++) {
    474      1.22   thorpej 		p = _nsvect_elem(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
    475      1.22   thorpej 		if (strcasecmp(dbt->name, p->name) == 0) {
    476       1.2     lukem 					/* overwrite existing entry */
    477      1.22   thorpej 			if (p->srclist != NULL)
    478      1.22   thorpej 				_nssrclist_free(&p->srclist, p->srclistsize);
    479      1.22   thorpej 			memmove(p, dbt, sizeof(*dbt));
    480      1.15     lukem 			return (0);
    481       1.2     lukem 		}
    482       1.2     lukem 	}
    483      1.22   thorpej 	new = _nsvect_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap));
    484      1.22   thorpej 	if (new == NULL)
    485      1.22   thorpej 		return (-1);
    486      1.22   thorpej 	_nsmap = new;
    487      1.22   thorpej 	/* _nsmapsize already incremented */
    488       1.2     lukem 
    489      1.22   thorpej 	return (0);
    490      1.22   thorpej }
    491      1.22   thorpej 
    492      1.22   thorpej /*
    493      1.22   thorpej  * This function is called each time nsdispatch() is called.  If this
    494      1.22   thorpej  * is the first call, or if the configuration has changed, (re-)prepare
    495      1.22   thorpej  * the global data used by NSS.
    496      1.22   thorpej  */
    497      1.22   thorpej static int
    498      1.22   thorpej _nsconfigure(void)
    499      1.22   thorpej {
    500      1.22   thorpej #ifdef _REENTRANT
    501      1.22   thorpej 	static mutex_t	_nsconflock = MUTEX_INITIALIZER;
    502      1.22   thorpej #endif
    503      1.22   thorpej 	static time_t	_nsconfmod;
    504      1.22   thorpej 	struct stat	statbuf;
    505      1.15     lukem 
    506      1.22   thorpej 	mutex_lock(&_nsconflock);
    507      1.22   thorpej 
    508      1.22   thorpej 	if (stat(_PATH_NS_CONF, &statbuf) == -1) {
    509      1.22   thorpej 		/*
    510      1.22   thorpej 		 * No nsswitch.conf; just use whatever configuration we
    511      1.22   thorpej 		 * currently have, or fall back on the defaults specified
    512      1.22   thorpej 		 * by the caller.
    513      1.22   thorpej 		 */
    514      1.22   thorpej 		mutex_unlock(&_nsconflock);
    515      1.22   thorpej 		return (0);
    516      1.22   thorpej 	}
    517      1.22   thorpej 
    518      1.22   thorpej 	if (statbuf.st_mtime <= _nsconfmod) {
    519      1.22   thorpej 		/* Internal state is up-to-date with nsswitch.conf. */
    520      1.22   thorpej 		mutex_unlock(&_nsconflock);
    521      1.22   thorpej 		return (0);
    522      1.22   thorpej 	}
    523      1.22   thorpej 
    524      1.22   thorpej 	/*
    525      1.22   thorpej 	 * Ok, we've decided we need to update the nsswitch configuration
    526      1.23   thorpej 	 * structures.  Acquire a write-lock on _nslock while continuing
    527      1.23   thorpej 	 * to hold _nsconflock.  Acquiring a write-lock blocks while
    528      1.23   thorpej 	 * waiting for other threads already holding a read-lock to clear.
    529      1.23   thorpej 	 * We hold _nsconflock for the duration, and update the time stamp
    530      1.23   thorpej 	 * at the end of the update operation, at which time we release
    531      1.23   thorpej 	 * both locks.
    532      1.22   thorpej 	 */
    533      1.22   thorpej 	rwlock_wrlock(&_nslock);
    534      1.22   thorpej 
    535      1.22   thorpej 	_nsyyin = fopen(_PATH_NS_CONF, "r");
    536      1.22   thorpej 	if (_nsyyin == NULL) {
    537      1.22   thorpej 		/*
    538      1.22   thorpej 		 * Unable to open nsswitch.conf; behave as though the
    539      1.22   thorpej 		 * stat() above failed.  Even though we have already
    540      1.22   thorpej 		 * updated _nsconfmod, if the file reappears, the
    541      1.22   thorpej 		 * mtime will change.
    542      1.22   thorpej 		 */
    543      1.23   thorpej 		goto out;
    544       1.2     lukem 	}
    545      1.22   thorpej 
    546      1.22   thorpej 	_NSVECT_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
    547      1.22   thorpej 	    (_nsvect_free_elem) _nsdbtfree);
    548      1.22   thorpej 	_NSVECT_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
    549      1.22   thorpej 	    (_nsvect_free_elem) _nsmodfree);
    550      1.22   thorpej 
    551      1.22   thorpej 	_nsloadbuiltin();
    552      1.22   thorpej 
    553      1.22   thorpej 	_nsyyparse();
    554      1.22   thorpej 	(void) fclose(_nsyyin);
    555      1.22   thorpej 	if (_nsmapsize != 0)
    556      1.22   thorpej 		qsort(_nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    557      1.23   thorpej 
    558      1.23   thorpej 	_nsconfmod = statbuf.st_mtime;
    559      1.23   thorpej 
    560      1.23   thorpej  out:
    561      1.22   thorpej 	rwlock_unlock(&_nslock);
    562      1.23   thorpej 	mutex_unlock(&_nsconflock);
    563      1.15     lukem 	return (0);
    564       1.2     lukem }
    565       1.2     lukem 
    566      1.22   thorpej static nss_method
    567      1.22   thorpej _nsmethod(const char *source, const char *database, const char *method,
    568      1.22   thorpej     const ns_dtab disp_tab[], void **cb_data)
    569      1.22   thorpej {
    570      1.22   thorpej 	int	curdisp;
    571      1.22   thorpej 	ns_mod	*mod, modkey;
    572      1.22   thorpej 	ns_mtab	*mtab, mtabkey;
    573      1.22   thorpej 
    574      1.22   thorpej 	if (disp_tab != NULL) {
    575      1.22   thorpej 		for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) {
    576      1.22   thorpej 			if (strcasecmp(source, disp_tab[curdisp].src) == 0) {
    577      1.22   thorpej 				*cb_data = disp_tab[curdisp].cb_data;
    578      1.22   thorpej 				return (disp_tab[curdisp].callback);
    579      1.22   thorpej 			}
    580      1.22   thorpej 		}
    581      1.22   thorpej 	}
    582      1.22   thorpej 
    583      1.22   thorpej 	modkey.name = source;
    584      1.22   thorpej 	mod = bsearch(&modkey, _nsmod, _nsmodsize, sizeof(*_nsmod),
    585      1.22   thorpej 	    _nsmodcmp);
    586      1.22   thorpej 	if (mod != NULL && mod->handle != NULL) {
    587      1.22   thorpej 		mtabkey.database = database;
    588      1.22   thorpej 		mtabkey.name = method;
    589      1.22   thorpej 		mtab = bsearch(&mtabkey, mod->mtab, mod->mtabsize,
    590      1.22   thorpej 		    sizeof(mod->mtab[0]), _nsmtabcmp);
    591      1.22   thorpej 		if (mtab != NULL) {
    592      1.22   thorpej 			*cb_data = mtab->mdata;
    593      1.22   thorpej 			return (mtab->method);
    594      1.22   thorpej 		}
    595      1.22   thorpej 	}
    596      1.22   thorpej 
    597      1.22   thorpej 	*cb_data = NULL;
    598      1.22   thorpej 	return (NULL);
    599      1.22   thorpej }
    600       1.2     lukem 
    601       1.2     lukem int
    602      1.11  christos /*ARGSUSED*/
    603       1.5     lukem nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
    604       1.5     lukem 	    const char *method, const ns_src defaults[], ...)
    605       1.2     lukem {
    606      1.23   thorpej 	static int	 _nsdispatching;
    607      1.23   thorpej #ifdef _REENTRANT
    608      1.23   thorpej 	struct _ns_drec	 drec, *ldrec;
    609      1.23   thorpej #endif
    610       1.2     lukem 	va_list		 ap;
    611      1.22   thorpej 	int		 i, result;
    612      1.22   thorpej 	ns_dbt		 key;
    613       1.2     lukem 	const ns_dbt	*dbt;
    614       1.5     lukem 	const ns_src	*srclist;
    615       1.5     lukem 	int		 srclistsize;
    616      1.22   thorpej 	nss_method	 cb;
    617      1.22   thorpej 	void		*cb_data;
    618      1.12     lukem 
    619      1.25     lukem 	/* retval may be NULL */
    620      1.25     lukem 	/* disp_tab may be NULL */
    621      1.12     lukem 	_DIAGASSERT(database != NULL);
    622      1.12     lukem 	_DIAGASSERT(method != NULL);
    623      1.25     lukem 	_DIAGASSERT(defaults != NULL);
    624      1.25     lukem 	if (database == NULL || method == NULL || defaults == NULL)
    625      1.12     lukem 		return (NS_UNAVAIL);
    626       1.2     lukem 
    627      1.23   thorpej 	/*
    628      1.23   thorpej 	 * In both the threaded and non-threaded cases, avoid reloading
    629      1.23   thorpej 	 * the configuration if the current thread is already running
    630      1.23   thorpej 	 * nsdispatch() (i.e. recursive call).
    631      1.23   thorpej 	 *
    632      1.23   thorpej 	 * In the non-threaded case, this avoids changing the data structures
    633      1.23   thorpej 	 * while we're using them.
    634      1.23   thorpej 	 *
    635      1.23   thorpej 	 * In the threaded case, this avoids trying to take a write lock
    636      1.23   thorpej 	 * while the current thread holds a read lock (which would result
    637      1.23   thorpej 	 * in deadlock).
    638      1.23   thorpej 	 */
    639      1.23   thorpej #ifdef _REENTRANT
    640      1.23   thorpej 	if (__isthreaded) {
    641      1.23   thorpej 		drec.thr = thr_self();
    642      1.23   thorpej 		mutex_lock(&_ns_drec_lock);
    643      1.23   thorpej 		LIST_FOREACH(ldrec, &_ns_drec, list) {
    644      1.23   thorpej 			if (ldrec->thr == drec.thr)
    645      1.23   thorpej 				break;
    646      1.23   thorpej 		}
    647      1.23   thorpej 		LIST_INSERT_HEAD(&_ns_drec, &drec, list);
    648      1.23   thorpej 		mutex_unlock(&_ns_drec_lock);
    649      1.23   thorpej 		if (ldrec == NULL && _nsconfigure()) {
    650      1.23   thorpej 			mutex_lock(&_ns_drec_lock);
    651      1.23   thorpej 			LIST_REMOVE(&drec, list);
    652      1.23   thorpej 			mutex_unlock(&_ns_drec_lock);
    653      1.23   thorpej 			return (NS_UNAVAIL);
    654      1.23   thorpej 		}
    655  1.28.2.1      tron 	} else
    656      1.23   thorpej #endif /* _REENTRANT */
    657  1.28.2.1      tron 	if (_nsdispatching++ == 0 && _nsconfigure()) {
    658  1.28.2.1      tron 		_nsdispatching--;
    659  1.28.2.1      tron 		return (NS_UNAVAIL);
    660  1.28.2.1      tron 	}
    661      1.22   thorpej 
    662      1.22   thorpej 	rwlock_rdlock(&_nslock);
    663      1.22   thorpej 
    664      1.22   thorpej 	key.name = database;
    665      1.22   thorpej 	dbt = bsearch(&key, _nsmap, _nsmapsize, sizeof(*_nsmap), _nsdbtcmp);
    666       1.5     lukem 	if (dbt != NULL) {
    667       1.5     lukem 		srclist = dbt->srclist;
    668       1.5     lukem 		srclistsize = dbt->srclistsize;
    669       1.5     lukem 	} else {
    670       1.5     lukem 		srclist = defaults;
    671       1.5     lukem 		srclistsize = 0;
    672       1.5     lukem 		while (srclist[srclistsize].name != NULL)
    673       1.5     lukem 			srclistsize++;
    674       1.5     lukem 	}
    675       1.2     lukem 	result = 0;
    676       1.2     lukem 
    677       1.5     lukem 	for (i = 0; i < srclistsize; i++) {
    678      1.22   thorpej 		cb = _nsmethod(srclist[i].name, database, method,
    679      1.22   thorpej 		    disp_tab, &cb_data);
    680       1.2     lukem 		result = 0;
    681      1.22   thorpej 		if (cb != NULL) {
    682       1.5     lukem 			va_start(ap, defaults);
    683      1.22   thorpej 			result = (*cb)(retval, cb_data, ap);
    684       1.2     lukem 			va_end(ap);
    685      1.26     lukem 			if (defaults[0].flags & NS_FORCEALL)
    686      1.26     lukem 				continue;
    687      1.22   thorpej 			if (result & srclist[i].flags)
    688       1.2     lukem 				break;
    689       1.2     lukem 		}
    690       1.2     lukem 	}
    691      1.27     lukem 	result &= NS_STATUSMASK;	/* clear private flags in result */
    692      1.22   thorpej 
    693      1.22   thorpej 	rwlock_unlock(&_nslock);
    694      1.22   thorpej 
    695      1.23   thorpej #ifdef _REENTRANT
    696      1.23   thorpej 	if (__isthreaded) {
    697      1.23   thorpej 		mutex_lock(&_ns_drec_lock);
    698      1.23   thorpej 		LIST_REMOVE(&drec, list);
    699      1.23   thorpej 		mutex_unlock(&_ns_drec_lock);
    700      1.23   thorpej 	} else
    701      1.23   thorpej #endif /* _REENTRANT */
    702  1.28.2.1      tron 		_nsdispatching--;
    703      1.23   thorpej 
    704       1.2     lukem 	return (result ? result : NS_NOTFOUND);
    705       1.2     lukem }
    706