xref: /onnv-gate/usr/src/lib/libc/port/gen/nss_common.c (revision 11411:c2fe1bf96826)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213864Sraf 
220Sstevel@tonic-gate /*
239170SRoger.Faulkner@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Shared code used by the name-service-switch frontends (e.g. getpwnam_r())
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
316812Sraf #include "lint.h"
320Sstevel@tonic-gate #include <mtlib.h>
330Sstevel@tonic-gate #include <dlfcn.h>
343864Sraf #include <atomic.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	__NSS_PRIVATE_INTERFACE
370Sstevel@tonic-gate #include "nsswitch_priv.h"
380Sstevel@tonic-gate #undef	__NSS_PRIVATE_INTERFACE
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <nss_common.h>
412830Sdjl #include <nss_dbdefs.h>
420Sstevel@tonic-gate #include <unistd.h>
430Sstevel@tonic-gate #include <stdlib.h>
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <string.h>
460Sstevel@tonic-gate #include <thread.h>
475891Sraf #include <synch.h>
485891Sraf #include <pthread.h>
492830Sdjl #include <sys/types.h>
502830Sdjl #include <sys/mman.h>
512830Sdjl #include <errno.h>
520Sstevel@tonic-gate #include "libc.h"
530Sstevel@tonic-gate #include "tsd.h"
540Sstevel@tonic-gate 
552830Sdjl #include <getxby_door.h>
562830Sdjl 
570Sstevel@tonic-gate /*
586279Sdjl  * configurable values for default buffer sizes
596279Sdjl  */
606279Sdjl 
616279Sdjl /*
626279Sdjl  * PSARC/2005/133 updated the buffering mechanisms to handle
636279Sdjl  * up to 2^64 buffering.  But sets a practical limit of 512*1024.
646279Sdjl  * the expectation is the practical limit will be dynamic from
656279Sdjl  * nscd.  For now, set the group limit to this value.
666279Sdjl  */
676279Sdjl 
686279Sdjl #define	NSS_BUFLEN_PRACTICAL	(512*1024)
696279Sdjl 
706279Sdjl static size_t __nss_buflen_group = NSS_BUFLEN_PRACTICAL;
716279Sdjl static size_t __nss_buflen_default = NSS_BUFLEN_DOOR;
726279Sdjl 
736279Sdjl /*
742830Sdjl  * policy component function interposing definitions:
752830Sdjl  * nscd if so desired can interpose it's own switch functions over
762830Sdjl  * the internal unlocked counterparts.  This will allow nscd to replace
772830Sdjl  * the switch policy state engine with one that uses it's internal
782830Sdjl  * components.
792830Sdjl  * Only nscd can change this through it's use of nss_config.
802830Sdjl  * The golden rule is: ptr == NULL checking is used in the switch to
812830Sdjl  * see if a function was interposed.  But nscd is responsible for seeing
822830Sdjl  * that mutex locking to change the values are observed when the data is
832830Sdjl  * changed.  Especially if it happens > once.  The switch does not lock
842830Sdjl  * the pointer with mutexs.
852830Sdjl  */
862830Sdjl 
872830Sdjl typedef struct {
882830Sdjl 	void	*p;
892830Sdjl #if 0
902830Sdjl 	void		(*nss_delete_fp)(nss_db_root_t *rootp);
912830Sdjl 	nss_status_t	(*nss_search_fp)(nss_db_root_t *rootp,
922830Sdjl 				nss_db_initf_t initf, int search_fnum,
932830Sdjl 				void *search_args);
942830Sdjl 	void		(*nss_setent_u_fp)(nss_db_root_t *,
952830Sdjl 				nss_db_initf_t, nss_getent_t *);
962830Sdjl 	nss_status_t	(*nss_getent_u_fp)(nss_db_root_t *,
972830Sdjl 				nss_db_initf_t, nss_getent_t *, void *);
982830Sdjl 	void		(*nss_endent_u_fp)(nss_db_root_t *,
992830Sdjl 				nss_db_initf_t, nss_getent_t *);
1002830Sdjl 	void		(*end_iter_u_fp)(nss_db_root_t *rootp,
1012830Sdjl 				struct nss_getent_context *contextp);
1022830Sdjl #endif
1032830Sdjl } nss_policyf_t;
1042830Sdjl 
1052830Sdjl static mutex_t nss_policyf_lock = DEFAULTMUTEX;
1062830Sdjl static nss_policyf_t nss_policyf_ptrs =
1072830Sdjl 	{ (void *)NULL };
1082830Sdjl 
1092830Sdjl /*
1102830Sdjl  * nsswitch db_root state machine definitions:
1110Sstevel@tonic-gate  * The golden rule is:  if you hold a pointer to an nss_db_state struct and
1120Sstevel@tonic-gate  * you don't hold the lock, you'd better have incremented the refcount
1130Sstevel@tonic-gate  * while you held the lock;  otherwise, it may vanish or change
1140Sstevel@tonic-gate  * significantly when you least expect it.
1150Sstevel@tonic-gate  *
1160Sstevel@tonic-gate  * The pointer in nss_db_root_t is one such, so the reference count >= 1.
1170Sstevel@tonic-gate  * Ditto the pointer in struct nss_getent_context.
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * State for one nsswitch database (e.g. "passwd", "hosts")
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate struct nss_db_state {
1240Sstevel@tonic-gate 	nss_db_root_t		orphan_root;	/* XXX explain */
1250Sstevel@tonic-gate 	unsigned		refcount;	/* One for the pointer in    */
1260Sstevel@tonic-gate 						/*   nss_db_root_t, plus one */
1270Sstevel@tonic-gate 						/*   for each active thread. */
1280Sstevel@tonic-gate 	nss_db_params_t		p;
1290Sstevel@tonic-gate 	struct __nsw_switchconfig_v1 *config;
1300Sstevel@tonic-gate 	int			max_src;	/* is == config->num_lookups */
1310Sstevel@tonic-gate 	struct nss_src_state	*src;		/* Pointer to array[max_src] */
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * State for one of the sources (e.g. "nis", "compat") for a database
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate struct nss_src_state {
1380Sstevel@tonic-gate 	struct __nsw_lookup_v1	*lkp;
1390Sstevel@tonic-gate 	int			n_active;
1400Sstevel@tonic-gate 	int			n_dormant;
1410Sstevel@tonic-gate 	int			n_waiting;	/* ... on wanna_be */
1420Sstevel@tonic-gate 	cond_t			wanna_be;
1430Sstevel@tonic-gate 	union {
1440Sstevel@tonic-gate 		nss_backend_t	*single; /* Efficiency hack for common case */
1450Sstevel@tonic-gate 					    /* when limit_dead_backends == 1 */
1460Sstevel@tonic-gate 		nss_backend_t	**multi; /* array[limit_dead_backends] of */
1470Sstevel@tonic-gate 	} dormant;			    /* pointers to dormant backends */
1480Sstevel@tonic-gate 	nss_backend_constr_t	be_constr;
1490Sstevel@tonic-gate 	nss_backend_finder_t	*finder;
1500Sstevel@tonic-gate 	void			*finder_priv;
1510Sstevel@tonic-gate };
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate static struct nss_db_state	*_nss_db_state_constr(nss_db_initf_t);
1540Sstevel@tonic-gate void				_nss_db_state_destr(struct nss_db_state *);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /* ==== null definitions if !MTSAFE?  Ditto lock field in nss_db_root_t */
1570Sstevel@tonic-gate 
1585891Sraf #define	NSS_ROOTLOCK(r, sp)	(cancel_safe_mutex_lock(&(r)->lock), \
1590Sstevel@tonic-gate 				*(sp) = (r)->s)
1600Sstevel@tonic-gate 
1615891Sraf #define	NSS_UNLOCK(r)		(cancel_safe_mutex_unlock(&(r)->lock))
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate #define	NSS_CHECKROOT(rp, s)	((s) != (*(rp))->s &&			\
1645891Sraf 			(cancel_safe_mutex_unlock(&(*(rp))->lock),	\
1655891Sraf 			cancel_safe_mutex_lock(&(s)->orphan_root.lock), \
1660Sstevel@tonic-gate 			*(rp) = &(s)->orphan_root))
1670Sstevel@tonic-gate 
1685891Sraf #define	NSS_RELOCK(rp, s)	(cancel_safe_mutex_lock(&(*(rp))->lock), \
1690Sstevel@tonic-gate 			NSS_CHECKROOT(rp, s))
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate #define	NSS_STATE_REF_u(s)	(++(s)->refcount)
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate #define	NSS_UNREF_UNLOCK(r, s)	(--(s)->refcount != 0			\
1740Sstevel@tonic-gate 			? ((void)NSS_UNLOCK(r))				\
1755891Sraf 			: ((void)NSS_UNLOCK(r), (void)_nss_db_state_destr(s)))
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate #define	NSS_LOCK_CHECK(r, f, sp)    (NSS_ROOTLOCK((r), (sp)),	\
1780Sstevel@tonic-gate 				    *(sp) == 0 &&		\
1790Sstevel@tonic-gate 				    (r->s = *(sp) = _nss_db_state_constr(f)))
1800Sstevel@tonic-gate /* === In the future, NSS_LOCK_CHECK() may also have to check that   */
1810Sstevel@tonic-gate /* === the config info hasn't changed (by comparing version numbers) */
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 
1842830Sdjl /*
1852830Sdjl  * NSS_OPTIONS/NIS_OPTIONS environment varibles data definitions:
1862830Sdjl  * This remains for backwards compatibility.  But generally nscd will
1872830Sdjl  * decide if/how this gets used.
1882830Sdjl  */
1890Sstevel@tonic-gate static int checked_env = 0;		/* protected by "rootlock" */
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* allowing __nss_debug_file to be set could be a security hole. */
1920Sstevel@tonic-gate FILE *__nss_debug_file = stdout;
1930Sstevel@tonic-gate int __nss_debug_eng_loop;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate /* NIS_OPTIONS infrastructure (from linbsl/nis/cache/cache_api.cc) */
1960Sstevel@tonic-gate 	/* allowing __nis_debug_file to be set could be a security hole. */
1970Sstevel@tonic-gate FILE *__nis_debug_file = stdout;
1980Sstevel@tonic-gate int __nis_debug_bind;
1990Sstevel@tonic-gate int __nis_debug_rpc;
2000Sstevel@tonic-gate int __nis_debug_calls;
2010Sstevel@tonic-gate char *__nis_prefsrv;
2020Sstevel@tonic-gate char *__nis_preftype;
2030Sstevel@tonic-gate char *__nis_server;   /* if set, use only this server for binding */
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate #define	OPT_INT 1
2060Sstevel@tonic-gate #define	OPT_STRING 2
2070Sstevel@tonic-gate #ifdef DEBUG
2080Sstevel@tonic-gate #define	OPT_FILE 3
2090Sstevel@tonic-gate #endif
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate struct option {
2120Sstevel@tonic-gate 	char *name;
2130Sstevel@tonic-gate 	int type;
2140Sstevel@tonic-gate 	void *address;
2150Sstevel@tonic-gate };
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate static struct option nss_options[] = {
2180Sstevel@tonic-gate #ifdef DEBUG
2190Sstevel@tonic-gate 	/* allowing __nss_debug_file to be set could be a security hole. */
2200Sstevel@tonic-gate 	{ "debug_file", OPT_FILE, &__nss_debug_file },
2210Sstevel@tonic-gate #endif
2220Sstevel@tonic-gate 	{ "debug_eng_loop", OPT_INT, &__nss_debug_eng_loop },
2230Sstevel@tonic-gate 	{ 0, 0, 0 },
2240Sstevel@tonic-gate };
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate static struct option nis_options[] = {
2270Sstevel@tonic-gate #ifdef DEBUG
2280Sstevel@tonic-gate 	/* allowing __nis_debug_file to be set could be a security hole. */
2290Sstevel@tonic-gate 	{ "debug_file", OPT_FILE, &__nis_debug_file },
2300Sstevel@tonic-gate #endif
2310Sstevel@tonic-gate 	{ "debug_bind", OPT_INT, &__nis_debug_bind },
2320Sstevel@tonic-gate 	{ "debug_rpc", OPT_INT, &__nis_debug_rpc },
2330Sstevel@tonic-gate 	{ "debug_calls", OPT_INT, &__nis_debug_calls },
2340Sstevel@tonic-gate 	{ "server", OPT_STRING, &__nis_server },
2350Sstevel@tonic-gate 	{ "pref_srvr", OPT_STRING, &__nis_prefsrv },
2360Sstevel@tonic-gate 	{ "pref_type", OPT_STRING, &__nis_preftype },
2370Sstevel@tonic-gate 	{ 0, 0, 0 },
2380Sstevel@tonic-gate };
2390Sstevel@tonic-gate 
2402830Sdjl /*
2412830Sdjl  * switch configuration parameter "database" definitions:
2422830Sdjl  * The switch maintains a simmple read/write parameter database
2432830Sdjl  * that nscd and the switch components can use to communicate
2442830Sdjl  * nscd data to other components for configuration or out of band
2452830Sdjl  * [IE no in the context of a getXbyY or putXbyY operation] data.
2462830Sdjl  * The data passed are pointers to a lock  data buffer and a length.
2472830Sdjl  * Use of this is treated as SunwPrivate between nscd and the switch
2482830Sdjl  * unless other wise stated.
2492830Sdjl  */
2502830Sdjl 
2512830Sdjl typedef struct nss_cfgparam {
2522830Sdjl 	char 		*name;
2532830Sdjl 	mutex_t		*lock;
2542830Sdjl 	void		*buffer;
2552830Sdjl 	size_t		length;
2562830Sdjl } nss_cfgparam_t;
2572830Sdjl 
2582830Sdjl typedef struct nss_cfglist {
2592830Sdjl 	char 		*name;
2602830Sdjl 	nss_cfgparam_t	*list;
2612830Sdjl 	int		count;
2622830Sdjl 	int		max;
2632830Sdjl } nss_cfglist_t;
2642830Sdjl 
2652830Sdjl #define	NSS_CFG_INCR	16
2662830Sdjl 
2673864Sraf static nss_cfglist_t *nss_cfg = NULL;
2682830Sdjl static int nss_cfgcount = 0;
2692830Sdjl static int nss_cfgmax = 0;
2702830Sdjl static mutex_t nss_cfglock = DEFAULTMUTEX;
2712830Sdjl 
2722830Sdjl static int nss_cfg_policy_init();
2732830Sdjl 
2742830Sdjl /*
2752830Sdjl  * A config parameters are in the form component:parameter
2762830Sdjl  * as in: nss:parameter - switch (internal FE/policy/BE) parameter
2772830Sdjl  *	  nscd:param - nscd application parameter
2782830Sdjl  *	  ldap:param - nss_ldap BE parameter
2792830Sdjl  *	  passwd:param - get/put passwd FE parameter
2802830Sdjl  */
2812830Sdjl 
2822830Sdjl #define	NSS_CONFIG_BRK	':'
2832830Sdjl 
2842830Sdjl /*
2852830Sdjl  * The policy components initial parameter list
2862830Sdjl  */
2872830Sdjl static nss_config_t	nss_policy_params[] = {
2882830Sdjl 	{ "nss:policyfunc", NSS_CONFIG_ADD, &nss_policyf_lock,
2892830Sdjl 		(void *)&nss_policyf_ptrs, (size_t)sizeof (nss_policyf_t) },
2902830Sdjl 	{ NULL,	NSS_CONFIG_ADD,	(mutex_t *)NULL, (void *)NULL, (size_t)0 },
2912830Sdjl };
2922830Sdjl 
2932830Sdjl /*
2942830Sdjl  * NSS parameter configuration routines
2952830Sdjl  */
2962830Sdjl 
2972830Sdjl /* compare config name (component:parameter) to a component name */
2982830Sdjl static int
nss_cfgcn_cmp(const char * cfgname,const char * compname)2992830Sdjl nss_cfgcn_cmp(const char *cfgname, const char *compname)
3002830Sdjl {
3012830Sdjl 	char *c;
3022830Sdjl 	size_t len, len2;
3032830Sdjl 
3042830Sdjl 	/* this code assumes valid pointers */
3052830Sdjl 	if ((c = strchr(cfgname, NSS_CONFIG_BRK)) == NULL)
3062830Sdjl 		return (-1);
3072830Sdjl 	len = (size_t)(c - cfgname);
3082830Sdjl 	len2 = strlen(compname);
3092830Sdjl 	if (len2 != len)
3102830Sdjl 		return (-1);
3112830Sdjl 	return (strncmp(cfgname, compname, len));
3122830Sdjl }
3132830Sdjl 
3142830Sdjl /* init configuration arena */
3152830Sdjl static int
nss_cfg_init()3162830Sdjl nss_cfg_init()
3172830Sdjl {
3183864Sraf 	nss_cfglist_t *cfg;
3192830Sdjl 	int i;
3202830Sdjl 
3212830Sdjl 	/* First time caller? */
3223864Sraf 	if (nss_cfg != NULL) {
3233864Sraf 		membar_consumer();
3242830Sdjl 		return (0);
3253864Sraf 	}
3262830Sdjl 
3272830Sdjl 	/* Initialize internal tables */
3282830Sdjl 	lmutex_lock(&nss_cfglock);
3292830Sdjl 	if (nss_cfg != NULL) {
3302830Sdjl 		lmutex_unlock(&nss_cfglock);
3313864Sraf 		membar_consumer();
3322830Sdjl 		return (0);
3332830Sdjl 	}
3343864Sraf 	cfg = libc_malloc(NSS_CFG_INCR * sizeof (nss_cfglist_t));
3353864Sraf 	if (cfg == NULL) {
3362830Sdjl 		errno = ENOMEM;
3372830Sdjl 		lmutex_unlock(&nss_cfglock);
3382830Sdjl 		return (-1);
3392830Sdjl 	}
3403864Sraf 	for (i = 0; i < NSS_CFG_INCR; i++) {
3413864Sraf 		cfg[i].list = libc_malloc(
3423864Sraf 		    NSS_CFG_INCR * sizeof (nss_cfgparam_t));
3433864Sraf 		if (cfg[i].list == NULL) {
3443864Sraf 			while (--i >= 0)
3453864Sraf 				libc_free(cfg[i].list);
3463864Sraf 			libc_free(cfg);
3472830Sdjl 			errno = ENOMEM;
3482830Sdjl 			lmutex_unlock(&nss_cfglock);
3492830Sdjl 			return (-1);
3502830Sdjl 		}
3513864Sraf 		cfg[i].max = NSS_CFG_INCR;
3522830Sdjl 	}
3533864Sraf 	nss_cfgmax = NSS_CFG_INCR;
3543864Sraf 	membar_producer();
3553864Sraf 	nss_cfg = cfg;
3563864Sraf 	lmutex_unlock(&nss_cfglock);
3572830Sdjl 
3582830Sdjl 	/* Initialize Policy Engine values */
3592830Sdjl 	if (nss_cfg_policy_init() < 0) {
3602830Sdjl 		return (-1);
3612830Sdjl 	}
3622830Sdjl 	return (0);
3632830Sdjl }
3642830Sdjl 
3652830Sdjl /* find the name'd component list - create it if non-existent */
3662830Sdjl static nss_cfglist_t *
nss_cfgcomp_get(char * name,int add)3672830Sdjl nss_cfgcomp_get(char *name, int add)
3682830Sdjl {
3692830Sdjl 	nss_cfglist_t	*next;
3702830Sdjl 	char	*c;
3712830Sdjl 	int	i, len;
3722830Sdjl 	size_t	nsize;
3732830Sdjl 
3742830Sdjl 	/* Make sure system is init'd */
3753864Sraf 	if (nss_cfg_init() < 0)
3762830Sdjl 		return ((nss_cfglist_t *)NULL);
3772830Sdjl 
3782830Sdjl 	/* and check component:name validity */
3792830Sdjl 	if (name == NULL || (c = strchr(name, NSS_CONFIG_BRK)) == NULL)
3802830Sdjl 		return ((nss_cfglist_t *)NULL);
3812830Sdjl 
3822830Sdjl 	lmutex_lock(&nss_cfglock);
3832830Sdjl 	next = nss_cfg;
3842830Sdjl 	for (i = 0; i < nss_cfgcount; i++) {
3852830Sdjl 		if (next->name && nss_cfgcn_cmp(name, next->name) == 0) {
3862830Sdjl 			lmutex_unlock(&nss_cfglock);
3872830Sdjl 			return (next);
3882830Sdjl 		}
3892830Sdjl 		next++;
3902830Sdjl 	}
3912830Sdjl 	if (!add) {
3922830Sdjl 		lmutex_unlock(&nss_cfglock);
3932830Sdjl 		return (NULL);
3942830Sdjl 	}
3952830Sdjl 
3962830Sdjl 	/* not found, create a fresh one */
3972830Sdjl 	if (nss_cfgcount >= nss_cfgmax) {
3982830Sdjl 		/* realloc first */
3992830Sdjl 		nsize = (nss_cfgmax + NSS_CFG_INCR) * sizeof (nss_cfgparam_t);
4002830Sdjl 		next = (nss_cfglist_t *)libc_realloc(nss_cfg, nsize);
4012830Sdjl 		if (next == NULL) {
4022830Sdjl 			errno = ENOMEM;
4032830Sdjl 			lmutex_unlock(&nss_cfglock);
4042830Sdjl 			return ((nss_cfglist_t *)NULL);
4052830Sdjl 		}
4062830Sdjl 		(void) memset((void *)(next + nss_cfgcount), '\0',
4076279Sdjl 		    NSS_CFG_INCR * sizeof (nss_cfglist_t));
4082830Sdjl 		nss_cfgmax += NSS_CFG_INCR;
4092830Sdjl 		nss_cfg = next;
4102830Sdjl 	}
4112830Sdjl 	next = nss_cfg + nss_cfgcount;
4122830Sdjl 	len = (size_t)(c - name) + 1;
4132830Sdjl 	if ((next->name = libc_malloc(len)) == NULL) {
4142830Sdjl 		errno = ENOMEM;
4152830Sdjl 		lmutex_unlock(&nss_cfglock);
4162830Sdjl 		return ((nss_cfglist_t *)NULL);
4172830Sdjl 	}
4182830Sdjl 	nss_cfgcount++;
4192830Sdjl 	(void) strlcpy(next->name, name, len);
4202830Sdjl 	lmutex_unlock(&nss_cfglock);
4212830Sdjl 	return (next);
4222830Sdjl }
4232830Sdjl 
4242830Sdjl /* find the name'd parameter - create it if non-existent */
4252830Sdjl static nss_cfgparam_t *
nss_cfgparam_get(char * name,int add)4262830Sdjl nss_cfgparam_get(char *name, int add)
4272830Sdjl {
4282830Sdjl 	nss_cfglist_t	*comp;
4292830Sdjl 	nss_cfgparam_t	*next;
4302830Sdjl 	int	count, i;
4312830Sdjl 	size_t	nsize;
4322830Sdjl 
4332830Sdjl 	if ((comp = nss_cfgcomp_get(name, add)) == NULL)
4342830Sdjl 		return ((nss_cfgparam_t *)NULL);
4352830Sdjl 	lmutex_lock(&nss_cfglock);
4362830Sdjl 	count = comp->count;
4372830Sdjl 	next = comp->list;
4382830Sdjl 	for (i = 0; i < count; i++) {
4392830Sdjl 		if (next->name && strcmp(name, next->name) == 0) {
4402830Sdjl 			lmutex_unlock(&nss_cfglock);
4412830Sdjl 			return (next);
4422830Sdjl 		}
4432830Sdjl 		next++;
4442830Sdjl 	}
4452830Sdjl 	if (!add) {
4462830Sdjl 		lmutex_unlock(&nss_cfglock);
4472830Sdjl 		return (NULL);
4482830Sdjl 	}
4492830Sdjl 
4502830Sdjl 	/* not found, create a fresh one */
4512830Sdjl 	if (count >= comp->max) {
4522830Sdjl 		/* realloc first */
4532830Sdjl 		nsize = (comp->max + NSS_CFG_INCR) * sizeof (nss_cfgparam_t);
4542830Sdjl 		next = (nss_cfgparam_t *)libc_realloc(comp->list, nsize);
4552830Sdjl 		if (next == NULL) {
4562830Sdjl 			errno = ENOMEM;
4572830Sdjl 			lmutex_unlock(&nss_cfglock);
4582830Sdjl 			return ((nss_cfgparam_t *)NULL);
4592830Sdjl 		}
4602830Sdjl 		comp->max += NSS_CFG_INCR;
4612830Sdjl 		comp->list = next;
4622830Sdjl 	}
4632830Sdjl 	next = comp->list + comp->count;
4642830Sdjl 	if ((next->name = libc_strdup(name)) == NULL) {
4652830Sdjl 		errno = ENOMEM;
4662830Sdjl 		lmutex_unlock(&nss_cfglock);
4672830Sdjl 		return ((nss_cfgparam_t *)NULL);
4682830Sdjl 	}
4692830Sdjl 	comp->count++;
4702830Sdjl 	lmutex_unlock(&nss_cfglock);
4712830Sdjl 	return (next);
4722830Sdjl }
4732830Sdjl 
4742830Sdjl /* find the name'd parameter - delete it if it exists */
4752830Sdjl static void
nss_cfg_del(nss_config_t * cfgp)4762830Sdjl nss_cfg_del(nss_config_t *cfgp)
4772830Sdjl {
4782830Sdjl 	char		*name;
4792830Sdjl 	nss_cfglist_t	*comp;
4802830Sdjl 	nss_cfgparam_t	*next, *cur;
4812830Sdjl 	int	count, i, j;
4822830Sdjl 
4832830Sdjl 	/* exit if component name does not already exist */
4842830Sdjl 	if ((name = cfgp->name) == NULL ||
4852830Sdjl 	    (comp = nss_cfgcomp_get(name, 0)) == NULL)
4862830Sdjl 		return;
4872830Sdjl 
4882830Sdjl 	/* find it */
4892830Sdjl 	lmutex_lock(&nss_cfglock);
4902830Sdjl 	count = comp->count;
4912830Sdjl 	next = comp->list;
4922830Sdjl 	for (i = 0; i < count; i++) {
4932830Sdjl 		if (next->name && strcmp(name, next->name) == 0) {
4942830Sdjl 			break;	/* found it... */
4952830Sdjl 		}
4962830Sdjl 		next++;
4972830Sdjl 	}
4982830Sdjl 	if (i >= count) {
4992830Sdjl 		/* not found, already deleted */
5002830Sdjl 		lmutex_unlock(&nss_cfglock);
5012830Sdjl 		return;
5022830Sdjl 	}
5032830Sdjl 
5042830Sdjl 	/* copy down the remaining parameters, and clean up */
5052830Sdjl 	/* don't try to clean up component tables */
5062830Sdjl 	cur = next;
5072830Sdjl 	next++;
5082830Sdjl 	for (j = i+1; j < count; j++) {
5092830Sdjl 		*cur = *next;
5102830Sdjl 		cur++;
5112830Sdjl 		next++;
5122830Sdjl 	}
5132830Sdjl 	/* erase the last one */
5142830Sdjl 	if (cur->name) {
5152830Sdjl 		libc_free(cur->name);
5162830Sdjl 		cur->name = (char *)NULL;
5172830Sdjl 	}
5182830Sdjl 	cur->lock = (mutex_t *)NULL;
5192830Sdjl 	cur->buffer = (void *)NULL;
5202830Sdjl 	cur->length = 0;
5212830Sdjl 	comp->count--;
5222830Sdjl 	lmutex_unlock(&nss_cfglock);
5232830Sdjl }
5242830Sdjl 
5252830Sdjl static int
nss_cfg_get(nss_config_t * next)5262830Sdjl nss_cfg_get(nss_config_t *next)
5272830Sdjl {
5282830Sdjl 	nss_cfgparam_t	*param;
5292830Sdjl 
5302830Sdjl 	errno = 0;
5312830Sdjl 	if ((param = nss_cfgparam_get(next->name, 0)) == NULL)
5322830Sdjl 		return (-1);
5332830Sdjl 	next->lock = param->lock;
5342830Sdjl 	next->buffer = param->buffer;
5352830Sdjl 	next->length = param->length;
5362830Sdjl 	return (0);
5372830Sdjl }
5382830Sdjl 
5392830Sdjl static int
nss_cfg_put(nss_config_t * next,int add)5402830Sdjl nss_cfg_put(nss_config_t *next, int add)
5412830Sdjl {
5422830Sdjl 	nss_cfgparam_t	*param;
5432830Sdjl 
5442830Sdjl 	errno = 0;
5452830Sdjl 	if ((param = nss_cfgparam_get(next->name, add)) == NULL)
5462830Sdjl 		return (-1);
5472830Sdjl 	param->lock = next->lock;
5482830Sdjl 	param->buffer = next->buffer;
5492830Sdjl 	param->length = next->length;
5502830Sdjl 	return (0);
5512830Sdjl }
5522830Sdjl 
5532830Sdjl /*
5542830Sdjl  * Policy engine configurator - set and get interface
5552830Sdjl  * argument is a NULL terminated list of set/get requests
5562830Sdjl  * with input/result buffers and lengths.  nss_cname is the
5572830Sdjl  * specifier of a set or get operation and the property being
5582830Sdjl  * managed.  The intent is limited functions and expandability.
5592830Sdjl  */
5602830Sdjl 
5612830Sdjl nss_status_t
nss_config(nss_config_t ** plist,int cnt)5622830Sdjl nss_config(nss_config_t **plist, int cnt)
5632830Sdjl {
5642830Sdjl 	nss_config_t	*next;
5652830Sdjl 	int 	i;
5662830Sdjl 
5672830Sdjl 	/* interface is only available to nscd */
5682830Sdjl 	if (_nsc_proc_is_cache() <= 0) {
5692830Sdjl 		return (NSS_UNAVAIL);
5702830Sdjl 	}
5712830Sdjl 	if (plist == NULL || cnt <= 0)
5722830Sdjl 		return (NSS_SUCCESS);
5732830Sdjl 	for (i = 0; i < cnt; i++) {
5742830Sdjl 		next = plist[i];
5752830Sdjl 		if (next == NULL)
5762830Sdjl 			break;
5772830Sdjl 		if (next->name == NULL) {
5782830Sdjl 			errno = EFAULT;
5792830Sdjl 			return (NSS_ERROR);
5802830Sdjl 		}
5812830Sdjl 		switch (next->cop) {
5822830Sdjl 		case NSS_CONFIG_GET:
5832830Sdjl 			/* get current lock/buffer/length fields */
5842830Sdjl 			if (nss_cfg_get(next) < 0) {
5852830Sdjl 				return (NSS_ERROR);
5862830Sdjl 			}
5872830Sdjl 			break;
5882830Sdjl 		case NSS_CONFIG_PUT:
5892830Sdjl 			/* set new lock/buffer/length fields */
5902830Sdjl 			if (nss_cfg_put(next, 0) < 0) {
5912830Sdjl 				return (NSS_ERROR);
5922830Sdjl 			}
5932830Sdjl 			break;
5942830Sdjl 		case NSS_CONFIG_ADD:
5952830Sdjl 			/* add parameter & set new lock/buffer/length fields */
5962830Sdjl 			if (nss_cfg_put(next, 1) < 0) {
5972830Sdjl 				return (NSS_ERROR);
5982830Sdjl 			}
5992830Sdjl 			break;
6002830Sdjl 		case NSS_CONFIG_DELETE:
6012830Sdjl 			/* delete parameter - should always work... */
6022830Sdjl 			nss_cfg_del(next);
6032830Sdjl 			break;
6042830Sdjl 		case NSS_CONFIG_LIST:
6052830Sdjl 			break;
6062830Sdjl 		default:
6072830Sdjl 			continue;
6082830Sdjl 		}
6092830Sdjl 	}
6102830Sdjl 	return (NSS_SUCCESS);
6112830Sdjl }
6122830Sdjl 
6132830Sdjl /*
6142830Sdjl  * This routine is called immediately after nss_cfg_init but prior to
6152830Sdjl  * any commands from nscd being processed.  The intent here is to
6162830Sdjl  * initialize the nss:* parameters allowed by the policy component
6172830Sdjl  * so that nscd can then proceed and modify them if so desired.
6182830Sdjl  *
6192830Sdjl  * We know we can only get here if we are nscd so we can skip the
6202830Sdjl  * preliminaries.
6212830Sdjl  */
6222830Sdjl 
6232830Sdjl static int
nss_cfg_policy_init()6242830Sdjl nss_cfg_policy_init()
6252830Sdjl {
6262830Sdjl 	nss_config_t	*next = &nss_policy_params[0];
6272830Sdjl 
6282830Sdjl 	for (; next && next->name != NULL; next++) {
6292830Sdjl 		if (nss_cfg_put(next, 1) < 0)
6302830Sdjl 			return (-1);
6312830Sdjl 	}
6322830Sdjl 	return (0);
6332830Sdjl }
6342830Sdjl 
6352830Sdjl /*
6362830Sdjl  * NSS_OPTION & NIS_OPTION environment variable functions
6372830Sdjl  */
6382830Sdjl 
6390Sstevel@tonic-gate static
6400Sstevel@tonic-gate void
set_option(struct option * opt,char * name,char * val)6410Sstevel@tonic-gate set_option(struct option *opt, char *name, char *val)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	int n;
6440Sstevel@tonic-gate 	char *p;
6450Sstevel@tonic-gate #ifdef DEBUG
6460Sstevel@tonic-gate 	FILE *fp;
6470Sstevel@tonic-gate #endif
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	for (; opt->name; opt++) {
6500Sstevel@tonic-gate 		if (strcmp(name, opt->name) == 0) {
6510Sstevel@tonic-gate 			switch (opt->type) {
6526279Sdjl 			case OPT_STRING:
6530Sstevel@tonic-gate 				p = libc_strdup(val);
6540Sstevel@tonic-gate 				*((char **)opt->address) = p;
6550Sstevel@tonic-gate 				break;
6560Sstevel@tonic-gate 
6576279Sdjl 			case OPT_INT:
6580Sstevel@tonic-gate 				if (strcmp(val, "") == 0)
6590Sstevel@tonic-gate 					n = 1;
6600Sstevel@tonic-gate 				else
6610Sstevel@tonic-gate 					n = atoi(val);
6620Sstevel@tonic-gate 				*((int *)opt->address) = n;
6630Sstevel@tonic-gate 				break;
6640Sstevel@tonic-gate #ifdef DEBUG
6656279Sdjl 			case OPT_FILE:
6661914Scasper 				fp = fopen(val, "wF");
6670Sstevel@tonic-gate 				*((FILE **)opt->address) = fp;
6680Sstevel@tonic-gate 				break;
6690Sstevel@tonic-gate #endif
6700Sstevel@tonic-gate 			}
6710Sstevel@tonic-gate 			break;
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 	}
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate static
6770Sstevel@tonic-gate void
__parse_environment(struct option * opt,char * p)6780Sstevel@tonic-gate __parse_environment(struct option *opt, char *p)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	char *base;
6810Sstevel@tonic-gate 	char optname[100];
6820Sstevel@tonic-gate 	char optval[100];
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	while (*p) {
6850Sstevel@tonic-gate 		while (isspace(*p))
6860Sstevel@tonic-gate 			p++;
6870Sstevel@tonic-gate 		if (*p == '\0')
6880Sstevel@tonic-gate 			break;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 		base = p;
6910Sstevel@tonic-gate 		while (*p && *p != '=' && !isspace(*p))
6920Sstevel@tonic-gate 			p++;
6930Sstevel@tonic-gate 		/*
6940Sstevel@tonic-gate 		 * play it safe and keep it simple, bail if an opt name
6950Sstevel@tonic-gate 		 * is too long.
6960Sstevel@tonic-gate 		 */
6970Sstevel@tonic-gate 		if ((p-base) >= sizeof (optname))
6980Sstevel@tonic-gate 			return;
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 		(void) strncpy(optname, base, p-base);
7010Sstevel@tonic-gate 		optname[p-base] = '\0';
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		if (*p == '=') {
7040Sstevel@tonic-gate 			p++;
7050Sstevel@tonic-gate 			base = p;
7060Sstevel@tonic-gate 			while (*p && !isspace(*p))
7070Sstevel@tonic-gate 				p++;
7080Sstevel@tonic-gate 			/*
7090Sstevel@tonic-gate 			 * play it safe and keep it simple, bail if an opt
7100Sstevel@tonic-gate 			 * value is too long.
7110Sstevel@tonic-gate 			 */
7120Sstevel@tonic-gate 			if ((p-base) >= sizeof (optval))
7130Sstevel@tonic-gate 				return;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 			(void) strncpy(optval, base, p-base);
7160Sstevel@tonic-gate 			optval[p-base] = '\0';
7170Sstevel@tonic-gate 		} else {
7180Sstevel@tonic-gate 			optval[0] = '\0';
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		set_option(opt, optname, optval);
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate static
7260Sstevel@tonic-gate void
nss_get_environment()7270Sstevel@tonic-gate nss_get_environment()
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	char *p;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate /* NSS_OPTIONS is undocumented and should be used without nscd running. */
7320Sstevel@tonic-gate 	p = getenv("NSS_OPTIONS");
7330Sstevel@tonic-gate 	if (p == NULL)
7340Sstevel@tonic-gate 		return;
7350Sstevel@tonic-gate 	__parse_environment(nss_options, p);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate  * sole external routine called from libnsl/nis/cache/cache_api.cc in the
7400Sstevel@tonic-gate  * routines _nis_CacheInit/__nis_CacheLocalInit/__nis_CacheMgrInit_discard
7410Sstevel@tonic-gate  * Only after checking "checked_env" (which must be done with mutex
7420Sstevel@tonic-gate  * "cur_cache_lock" held) and is done once, (then "checked_env" is set)
7430Sstevel@tonic-gate  */
7440Sstevel@tonic-gate void
__nis_get_environment()7450Sstevel@tonic-gate __nis_get_environment()
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	char *p;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	p = getenv("NIS_OPTIONS");
7500Sstevel@tonic-gate 	if (p == NULL)
7510Sstevel@tonic-gate 		return;
7520Sstevel@tonic-gate 	__parse_environment(nis_options, p);
7530Sstevel@tonic-gate }
7542830Sdjl 
7550Sstevel@tonic-gate 
7562830Sdjl /*
7572830Sdjl  * Switch policy component backend state machine functions
7582830Sdjl  */
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate static nss_backend_t *
nss_get_backend_u(nss_db_root_t ** rootpp,struct nss_db_state * s,int n_src)7610Sstevel@tonic-gate nss_get_backend_u(nss_db_root_t **rootpp, struct nss_db_state *s, int n_src)
7620Sstevel@tonic-gate {
7630Sstevel@tonic-gate 	struct nss_src_state	*src = &s->src[n_src];
7640Sstevel@tonic-gate 	nss_backend_t		*be;
7655891Sraf 	int cancel_state;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	for (;;) {
7680Sstevel@tonic-gate 		if (src->n_dormant > 0) {
7690Sstevel@tonic-gate 			src->n_dormant--;
7700Sstevel@tonic-gate 			src->n_active++;
7710Sstevel@tonic-gate 			if (s->p.max_dormant_per_src == 1) {
7720Sstevel@tonic-gate 				be = src->dormant.single;
7730Sstevel@tonic-gate 			} else {
7740Sstevel@tonic-gate 				be = src->dormant.multi[src->n_dormant];
7750Sstevel@tonic-gate 			}
7760Sstevel@tonic-gate 			break;
7770Sstevel@tonic-gate 		}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 		if (src->be_constr == 0) {
7800Sstevel@tonic-gate 			nss_backend_finder_t	*bf;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 			for (bf = s->p.finders;  bf != 0;  bf = bf->next) {
7830Sstevel@tonic-gate 				nss_backend_constr_t c;
7840Sstevel@tonic-gate 
7856279Sdjl 				c = (*bf->lookup) (bf->lookup_priv, s->p.name,
7866279Sdjl 				    src->lkp->service_name, &src->finder_priv);
7870Sstevel@tonic-gate 				if (c != 0) {
7880Sstevel@tonic-gate 					src->be_constr = c;
7890Sstevel@tonic-gate 					src->finder = bf;
7900Sstevel@tonic-gate 					break;
7910Sstevel@tonic-gate 				}
7920Sstevel@tonic-gate 			}
7930Sstevel@tonic-gate 			if (src->be_constr == 0) {
7940Sstevel@tonic-gate 				/* Couldn't find the backend anywhere */
7950Sstevel@tonic-gate 				be = 0;
7960Sstevel@tonic-gate 				break;
7970Sstevel@tonic-gate 			}
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 		if (src->n_active < s->p.max_active_per_src) {
8010Sstevel@tonic-gate 			be = (*src->be_constr)(s->p.name,
8026279Sdjl 			    src->lkp->service_name, 0 /* === unimplemented */);
8030Sstevel@tonic-gate 			if (be != 0) {
8040Sstevel@tonic-gate 				src->n_active++;
8050Sstevel@tonic-gate 				break;
8060Sstevel@tonic-gate 			} else if (src->n_active == 0) {
8070Sstevel@tonic-gate 				/* Something's wrong;  we should be */
8080Sstevel@tonic-gate 				/*   able to create at least one    */
8090Sstevel@tonic-gate 				/*   instance of the backend	    */
8100Sstevel@tonic-gate 				break;
8110Sstevel@tonic-gate 			}
8120Sstevel@tonic-gate 			/*
8130Sstevel@tonic-gate 			 * Else it's odd that we can't create another backend
8140Sstevel@tonic-gate 			 *   instance, but don't sweat it;  instead, queue for
8150Sstevel@tonic-gate 			 *   an existing backend instance.
8160Sstevel@tonic-gate 			 */
8170Sstevel@tonic-gate 		}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 		src->n_waiting++;
8205891Sraf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
8215891Sraf 		    &cancel_state);
8220Sstevel@tonic-gate 		(void) cond_wait(&src->wanna_be, &(*rootpp)->lock);
8235891Sraf 		(void) pthread_setcancelstate(cancel_state, NULL);
8240Sstevel@tonic-gate 		NSS_CHECKROOT(rootpp, s);
8250Sstevel@tonic-gate 		src->n_waiting--;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		/*
8280Sstevel@tonic-gate 		 * Loop and see whether things got better for us, or whether
8290Sstevel@tonic-gate 		 *   someone else got scheduled first and we have to try
8300Sstevel@tonic-gate 		 *   this again.
8310Sstevel@tonic-gate 		 *
8320Sstevel@tonic-gate 		 * === ?? Should count iterations, assume bug if many ??
8330Sstevel@tonic-gate 		 */
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	return (be);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate static void
nss_put_backend_u(struct nss_db_state * s,int n_src,nss_backend_t * be)8390Sstevel@tonic-gate nss_put_backend_u(struct nss_db_state *s, int n_src, nss_backend_t *be)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	struct nss_src_state	*src = &s->src[n_src];
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	if (be == 0) {
8440Sstevel@tonic-gate 		return;
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	src->n_active--;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (src->n_dormant < s->p.max_dormant_per_src) {
8500Sstevel@tonic-gate 		if (s->p.max_dormant_per_src == 1) {
8510Sstevel@tonic-gate 			src->dormant.single = be;
8520Sstevel@tonic-gate 			src->n_dormant++;
8530Sstevel@tonic-gate 		} else if (src->dormant.multi != 0 ||
8546279Sdjl 		    (src->dormant.multi =
8556279Sdjl 		    libc_malloc(s->p.max_dormant_per_src *
8566279Sdjl 		    sizeof (nss_backend_t *))) != NULL) {
8570Sstevel@tonic-gate 			src->dormant.multi[src->n_dormant] = be;
8580Sstevel@tonic-gate 			src->n_dormant++;
8590Sstevel@tonic-gate 		} else {
8600Sstevel@tonic-gate 			/* Can't store it, so toss it */
8610Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0);
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 	} else {
8640Sstevel@tonic-gate 		/* We've stored as many as we want, so toss it */
8650Sstevel@tonic-gate 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0);
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 	if (src->n_waiting > 0) {
8680Sstevel@tonic-gate 		(void) cond_signal(&src->wanna_be);
8690Sstevel@tonic-gate 	}
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate static struct nss_db_state *
_nss_db_state_constr(nss_db_initf_t initf)8730Sstevel@tonic-gate _nss_db_state_constr(nss_db_initf_t initf)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	struct nss_db_state	*s;
8760Sstevel@tonic-gate 	struct __nsw_switchconfig_v1 *config = 0;
8770Sstevel@tonic-gate 	struct __nsw_lookup_v1	*lkp;
8780Sstevel@tonic-gate 	enum __nsw_parse_err	err;
8790Sstevel@tonic-gate 	const char		*config_name;
8800Sstevel@tonic-gate 	int			n_src;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if ((s = libc_malloc(sizeof (*s))) == 0) {
8830Sstevel@tonic-gate 		return (0);
8840Sstevel@tonic-gate 	}
8856515Sraf 	(void) mutex_init(&s->orphan_root.lock, USYNC_THREAD, 0);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	s->p.max_active_per_src	= 10;
8880Sstevel@tonic-gate 	s->p.max_dormant_per_src = 1;
8890Sstevel@tonic-gate 	s->p.finders = nss_default_finders;
8900Sstevel@tonic-gate 	(*initf)(&s->p);
8910Sstevel@tonic-gate 	if (s->p.name == 0) {
8920Sstevel@tonic-gate 		_nss_db_state_destr(s);
8930Sstevel@tonic-gate 		return (0);
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	if (!checked_env) {
8970Sstevel@tonic-gate /* NSS_OPTIONS is undocumented and should be used without nscd running. */
8980Sstevel@tonic-gate 		nss_get_environment();
8990Sstevel@tonic-gate 		checked_env = 1;
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	config_name = s->p.config_name ? s->p.config_name : s->p.name;
9030Sstevel@tonic-gate 	if (! (s->p.flags & NSS_USE_DEFAULT_CONFIG)) {
9040Sstevel@tonic-gate 		config = __nsw_getconfig_v1(config_name, &err);
9050Sstevel@tonic-gate 		/* === ? test err ? */
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 	if (config == 0) {
9080Sstevel@tonic-gate 		/* getconfig failed, or frontend demanded default config */
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 		char	*str;	/* _nsw_getoneconfig() clobbers its argument */
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		if ((str = libc_strdup(s->p.default_config)) != 0) {
9130Sstevel@tonic-gate 			config = _nsw_getoneconfig_v1(config_name, str, &err);
9140Sstevel@tonic-gate 			libc_free(str);
9150Sstevel@tonic-gate 		}
9160Sstevel@tonic-gate 		if (config == 0) {
9170Sstevel@tonic-gate 			_nss_db_state_destr(s);
9180Sstevel@tonic-gate 			return (0);
9190Sstevel@tonic-gate 		}
9200Sstevel@tonic-gate 	}
9210Sstevel@tonic-gate 	s->config = config;
9220Sstevel@tonic-gate 	if ((s->max_src = config->num_lookups) <= 0 ||
9230Sstevel@tonic-gate 	    (s->src = libc_malloc(s->max_src * sizeof (*s->src))) == 0) {
9240Sstevel@tonic-gate 		_nss_db_state_destr(s);
9250Sstevel@tonic-gate 		return (0);
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 	for (n_src = 0, lkp = config->lookups;
9280Sstevel@tonic-gate 	    n_src < s->max_src; n_src++, lkp = lkp->next) {
9290Sstevel@tonic-gate 		s->src[n_src].lkp = lkp;
9300Sstevel@tonic-gate 		(void) cond_init(&s->src[n_src].wanna_be, USYNC_THREAD, 0);
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 	s->refcount = 1;
9330Sstevel@tonic-gate 	return (s);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate void
_nss_src_state_destr(struct nss_src_state * src,int max_dormant)9370Sstevel@tonic-gate _nss_src_state_destr(struct nss_src_state *src, int max_dormant)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	if (max_dormant == 1) {
9400Sstevel@tonic-gate 		if (src->n_dormant != 0) {
9410Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(src->dormant.single,
9426279Sdjl 			    NSS_DBOP_DESTRUCTOR, 0);
9430Sstevel@tonic-gate 		};
9440Sstevel@tonic-gate 	} else if (src->dormant.multi != 0) {
9450Sstevel@tonic-gate 		int	n;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 		for (n = 0;  n < src->n_dormant;  n++) {
9480Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(src->dormant.multi[n],
9496279Sdjl 			    NSS_DBOP_DESTRUCTOR, 0);
9500Sstevel@tonic-gate 		}
9510Sstevel@tonic-gate 		libc_free(src->dormant.multi);
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/* cond_destroy(&src->wanna_be); */
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	if (src->finder != 0) {
9570Sstevel@tonic-gate 		(*src->finder->delete)(src->finder_priv, src->be_constr);
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate  * _nss_db_state_destr() -- used by NSS_UNREF_UNLOCK() to free the entire
9630Sstevel@tonic-gate  *	nss_db_state structure.
9640Sstevel@tonic-gate  * Assumes that s has been ref-counted down to zero (in particular,
9650Sstevel@tonic-gate  *	rootp->s has already been dealt with).
9660Sstevel@tonic-gate  *
9670Sstevel@tonic-gate  * Nobody else holds a pointer to *s (if they did, refcount != 0),
9680Sstevel@tonic-gate  *   so we can clean up state *after* we drop the lock (also, by the
9690Sstevel@tonic-gate  *   time we finish freeing the state structures, the lock may have
9700Sstevel@tonic-gate  *   ceased to exist -- if we were using the orphan_root).
9710Sstevel@tonic-gate  */
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate void
_nss_db_state_destr(struct nss_db_state * s)9740Sstevel@tonic-gate _nss_db_state_destr(struct nss_db_state *s)
9750Sstevel@tonic-gate {
9762830Sdjl 
9772830Sdjl 	if (s == NULL)
9782830Sdjl 		return;
9792830Sdjl 
9806515Sraf 	/* === mutex_destroy(&s->orphan_root.lock); */
9810Sstevel@tonic-gate 	if (s->p.cleanup != 0) {
9820Sstevel@tonic-gate 		(*s->p.cleanup)(&s->p);
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 	if (s->config != 0) {
9850Sstevel@tonic-gate 		(void) __nsw_freeconfig_v1(s->config);
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 	if (s->src != 0) {
9880Sstevel@tonic-gate 		int	n_src;
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		for (n_src = 0;  n_src < s->max_src;  n_src++) {
9910Sstevel@tonic-gate 			_nss_src_state_destr(&s->src[n_src],
9926279Sdjl 			    s->p.max_dormant_per_src);
9930Sstevel@tonic-gate 		}
9940Sstevel@tonic-gate 		libc_free(s->src);
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 	libc_free(s);
9970Sstevel@tonic-gate }
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate  * _nss_status_vec() returns a bit vector of all status codes returned during
10020Sstevel@tonic-gate  * the most recent call to nss_search().
10030Sstevel@tonic-gate  * _nss_status_vec_p() returns a pointer to this bit vector, or NULL on
10040Sstevel@tonic-gate  * failure.
10050Sstevel@tonic-gate  * These functions are private.  Don't use them externally without discussing
10060Sstevel@tonic-gate  * it with the switch maintainers.
10070Sstevel@tonic-gate  */
10080Sstevel@tonic-gate static uint_t *
_nss_status_vec_p()10090Sstevel@tonic-gate _nss_status_vec_p()
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate 	return (tsdalloc(_T_NSS_STATUS_VEC, sizeof (uint_t), NULL));
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate unsigned int
_nss_status_vec(void)10150Sstevel@tonic-gate _nss_status_vec(void)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	unsigned int *status_vec_p = _nss_status_vec_p();
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	return ((status_vec_p != NULL) ? *status_vec_p : (1 << NSS_UNAVAIL));
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate static void
output_loop_diag_a(int n,char * dbase,struct __nsw_lookup_v1 * lkp)10230Sstevel@tonic-gate output_loop_diag_a(
10240Sstevel@tonic-gate 	int n,
10250Sstevel@tonic-gate 	char *dbase,
10260Sstevel@tonic-gate 	struct __nsw_lookup_v1 *lkp)
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	(void) fprintf(__nss_debug_file,
10300Sstevel@tonic-gate 		"NSS_retry(%d): '%s': trying '%s' ... ",
10310Sstevel@tonic-gate 		n, dbase, lkp->service_name);
10320Sstevel@tonic-gate 	(void) fflush(__nss_debug_file);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate static void
output_loop_diag_b(nss_status_t res,struct __nsw_lookup_v1 * lkp)10370Sstevel@tonic-gate output_loop_diag_b(
10380Sstevel@tonic-gate 	nss_status_t res,
10390Sstevel@tonic-gate 	struct __nsw_lookup_v1 *lkp)
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate {
10420Sstevel@tonic-gate 	(void) fprintf(__nss_debug_file, "result=");
10430Sstevel@tonic-gate 	switch (res) {
10440Sstevel@tonic-gate 	case NSS_SUCCESS:
10450Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "SUCCESS");
10460Sstevel@tonic-gate 		break;
10470Sstevel@tonic-gate 	case NSS_NOTFOUND:
10480Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "NOTFOUND");
10490Sstevel@tonic-gate 		break;
10500Sstevel@tonic-gate 	case NSS_UNAVAIL:
10510Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "UNAVAIL");
10520Sstevel@tonic-gate 		break;
10530Sstevel@tonic-gate 	case NSS_TRYAGAIN:
10540Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "TRYAGAIN");
10550Sstevel@tonic-gate 		break;
10560Sstevel@tonic-gate 	case NSS_NISSERVDNS_TRYAGAIN:
10570Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "NISSERVDNS_TRYAGAIN");
10580Sstevel@tonic-gate 		break;
10590Sstevel@tonic-gate 	default:
10600Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "undefined");
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 	(void) fprintf(__nss_debug_file, ", action=");
10630Sstevel@tonic-gate 	switch (lkp->actions[res]) {
10640Sstevel@tonic-gate 	case __NSW_CONTINUE:
10650Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "CONTINUE");
10660Sstevel@tonic-gate 		break;
10670Sstevel@tonic-gate 	case  __NSW_RETURN:
10680Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "RETURN");
10690Sstevel@tonic-gate 		break;
10700Sstevel@tonic-gate 	case __NSW_TRYAGAIN_FOREVER:
10710Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "TRYAGAIN_FOREVER");
10720Sstevel@tonic-gate 		break;
10730Sstevel@tonic-gate 	case __NSW_TRYAGAIN_NTIMES:
10740Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "TRYAGAIN_NTIMES (N=%d)",
10750Sstevel@tonic-gate 			lkp->max_retries);
10760Sstevel@tonic-gate 		break;
10770Sstevel@tonic-gate 	case __NSW_TRYAGAIN_PAUSED:
10780Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "TRYAGAIN_PAUSED");
10790Sstevel@tonic-gate 		break;
10800Sstevel@tonic-gate 	default:
10810Sstevel@tonic-gate 		(void) fprintf(__nss_debug_file, "undefined");
10820Sstevel@tonic-gate 	}
10830Sstevel@tonic-gate 	(void) fprintf(__nss_debug_file, "\n");
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate #define	NSS_BACKOFF(n, b, t) \
10870Sstevel@tonic-gate 			((n) > ((b) + 3) ? t : (1 << ((n) - ((b) + 1))))
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate static int
retry_test(nss_status_t res,int n,struct __nsw_lookup_v1 * lkp)10900Sstevel@tonic-gate retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp)
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	if (res != NSS_TRYAGAIN && res !=  NSS_NISSERVDNS_TRYAGAIN) {
10930Sstevel@tonic-gate 		if (res == NSS_SUCCESS) {
10940Sstevel@tonic-gate 			__NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]);
10950Sstevel@tonic-gate 			__NSW_UNPAUSE_ACTION(
10966279Sdjl 			    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]);
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 		return (0);
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	if ((res == NSS_TRYAGAIN &&
11020Sstevel@tonic-gate 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) ||
11030Sstevel@tonic-gate 	    (res == NSS_NISSERVDNS_TRYAGAIN &&
11040Sstevel@tonic-gate 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER))
11050Sstevel@tonic-gate 		return (1);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if (res == NSS_TRYAGAIN &&
11080Sstevel@tonic-gate 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
11090Sstevel@tonic-gate 		if (n <= lkp->max_retries)
11100Sstevel@tonic-gate 			return (1);
11110Sstevel@tonic-gate 		else {
11120Sstevel@tonic-gate 			lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED;
11130Sstevel@tonic-gate 			return (0);
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	if (res == NSS_NISSERVDNS_TRYAGAIN &&
11170Sstevel@tonic-gate 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
11180Sstevel@tonic-gate 		if (n <= lkp->max_retries)
11190Sstevel@tonic-gate 			return (1);
11200Sstevel@tonic-gate 		else {
11210Sstevel@tonic-gate 			lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] =
11220Sstevel@tonic-gate 			    __NSW_TRYAGAIN_PAUSED;
11230Sstevel@tonic-gate 			return (0);
11240Sstevel@tonic-gate 		}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (0);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11292830Sdjl /*
11302830Sdjl  * Switch policy component functional interfaces
11312830Sdjl  */
11322830Sdjl 
11332830Sdjl void
nss_delete(nss_db_root_t * rootp)11342830Sdjl nss_delete(nss_db_root_t *rootp)
11352830Sdjl {
11362830Sdjl 	struct nss_db_state	*s;
11372830Sdjl 
11382830Sdjl 	/* no name service cache daemon divert here */
11392830Sdjl 	/* local nss_delete decrements state reference counts */
11402830Sdjl 	/* and may free up opened switch resources. */
11412830Sdjl 
11422830Sdjl 	NSS_ROOTLOCK(rootp, &s);
11432830Sdjl 	if (s == 0) {
11442830Sdjl 		NSS_UNLOCK(rootp);
11452830Sdjl 	} else {
11462830Sdjl 		rootp->s = 0;
11472830Sdjl 		NSS_UNREF_UNLOCK(rootp, s);
11482830Sdjl 	}
11492830Sdjl }
11502830Sdjl 
11510Sstevel@tonic-gate nss_status_t
nss_search(nss_db_root_t * rootp,nss_db_initf_t initf,int search_fnum,void * search_args)11520Sstevel@tonic-gate nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
11530Sstevel@tonic-gate 	void *search_args)
11540Sstevel@tonic-gate {
11550Sstevel@tonic-gate 	nss_status_t		res = NSS_UNAVAIL;
11560Sstevel@tonic-gate 	struct nss_db_state	*s;
11570Sstevel@tonic-gate 	int			n_src;
11582830Sdjl 	unsigned int		*status_vec_p;
11592830Sdjl 
11602830Sdjl 	/* name service cache daemon divert */
11612830Sdjl 	res = _nsc_search(rootp, initf, search_fnum, search_args);
11622830Sdjl 	if (res != NSS_TRYLOCAL)
11632830Sdjl 		return (res);
11642830Sdjl 
11652830Sdjl 	/* fall through - process locally */
11662830Sdjl 	errno = 0;			/* just in case ... */
11672830Sdjl 	res = NSS_UNAVAIL;
11682830Sdjl 	status_vec_p = _nss_status_vec_p();
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (status_vec_p == NULL) {
11710Sstevel@tonic-gate 		return (NSS_UNAVAIL);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 	*status_vec_p = 0;
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	NSS_LOCK_CHECK(rootp, initf, &s);
11760Sstevel@tonic-gate 	if (s == 0) {
11770Sstevel@tonic-gate 		NSS_UNLOCK(rootp);
11780Sstevel@tonic-gate 		return (res);
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate 	NSS_STATE_REF_u(s);
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	for (n_src = 0;  n_src < s->max_src;  n_src++) {
11830Sstevel@tonic-gate 		nss_backend_t		*be;
11840Sstevel@tonic-gate 		nss_backend_op_t	funcp;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 		res = NSS_UNAVAIL;
11870Sstevel@tonic-gate 		if ((be = nss_get_backend_u(&rootp, s, n_src)) != 0) {
11880Sstevel@tonic-gate 			if ((funcp = NSS_LOOKUP_DBOP(be, search_fnum)) != 0) {
11890Sstevel@tonic-gate 				int n_loop = 0;
11900Sstevel@tonic-gate 				int no_backoff = 19;
11910Sstevel@tonic-gate 				int max_backoff = 5;	/* seconds */
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 				do {
11940Sstevel@tonic-gate 					/*
11950Sstevel@tonic-gate 					 * Backend operation may take a while;
11960Sstevel@tonic-gate 					 * drop the lock so we don't serialize
11970Sstevel@tonic-gate 					 * more than necessary.
11980Sstevel@tonic-gate 					 */
11990Sstevel@tonic-gate 					NSS_UNLOCK(rootp);
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 					/* After several tries, backoff... */
12020Sstevel@tonic-gate 					if (n_loop > no_backoff) {
12036279Sdjl 						if (__nss_debug_eng_loop > 1)
12046279Sdjl 							(void) fprintf(
12056279Sdjl 							    __nss_debug_file,
12066279Sdjl 							    "NSS: loop: "
12076279Sdjl 							    "sleeping %d ...\n",
12086279Sdjl 							    NSS_BACKOFF(n_loop,
12096279Sdjl 							    no_backoff,
12106279Sdjl 							    max_backoff));
12110Sstevel@tonic-gate 
12126279Sdjl 						(void) sleep(NSS_BACKOFF(n_loop,
12130Sstevel@tonic-gate 						    no_backoff, max_backoff));
12140Sstevel@tonic-gate 					}
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 					if (__nss_debug_eng_loop)
12170Sstevel@tonic-gate 						output_loop_diag_a(n_loop,
12186279Sdjl 						    s->config->dbase,
12196279Sdjl 						    s->src[n_src].lkp);
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 					res = (*funcp)(be, search_args);
12230Sstevel@tonic-gate 					NSS_RELOCK(&rootp, s);
12240Sstevel@tonic-gate 					n_loop++;
12250Sstevel@tonic-gate 					if (__nss_debug_eng_loop)
12260Sstevel@tonic-gate 						output_loop_diag_b(res,
12276279Sdjl 						    s->src[n_src].lkp);
12280Sstevel@tonic-gate 				} while (retry_test(res, n_loop,
12296279Sdjl 				    s->src[n_src].lkp));
12300Sstevel@tonic-gate 			}
12310Sstevel@tonic-gate 			nss_put_backend_u(s, n_src, be);
12320Sstevel@tonic-gate 		}
12330Sstevel@tonic-gate 		*status_vec_p |= (1 << res);
12340Sstevel@tonic-gate 		if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) {
12350Sstevel@tonic-gate 			if (__nss_debug_eng_loop)
12360Sstevel@tonic-gate 				(void) fprintf(__nss_debug_file,
12376279Sdjl 				    "NSS: '%s': return.\n",
12386279Sdjl 				    s->config->dbase);
12390Sstevel@tonic-gate 			break;
12400Sstevel@tonic-gate 		} else
12410Sstevel@tonic-gate 			if (__nss_debug_eng_loop)
12420Sstevel@tonic-gate 				(void) fprintf(__nss_debug_file,
12436279Sdjl 				    "NSS: '%s': continue ...\n",
12446279Sdjl 				    s->config->dbase);
12450Sstevel@tonic-gate 	}
12460Sstevel@tonic-gate 	NSS_UNREF_UNLOCK(rootp, s);
12470Sstevel@tonic-gate 	return (res);
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate /*
12522830Sdjl  * Start of nss_{setent|getent|endent}
12530Sstevel@tonic-gate  */
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate /*
12560Sstevel@tonic-gate  * State (here called "context") for one setent/getent.../endent sequence.
12570Sstevel@tonic-gate  *   In principle there could be multiple contexts active for a single
12580Sstevel@tonic-gate  *   database;  in practice, since Posix and UI have helpfully said that
12590Sstevel@tonic-gate  *   getent() state is global rather than, say, per-thread or user-supplied,
12600Sstevel@tonic-gate  *   we have at most one of these per nss_db_state.
12612830Sdjl  *   XXX ? Is this statement still true?
12622830Sdjl  *
12632830Sdjl  * NSS2 - a client's context is maintained as a cookie delivered by and
12642830Sdjl  * passed to nscd.  The cookie is a 64 bit (nssuint_t) unique opaque value
12652830Sdjl  * created by nscd.
12662830Sdjl  * cookie states:
12672830Sdjl  *	NSCD_NEW_COOKIE		- cookie value uninitialized
12682830Sdjl  *	NSCD_LOCAL_COOKIE	- setent is a local setent
12692830Sdjl  *	all other		- NSCD unique opaque id for this setent
12702830Sdjl  * A client's context is also associated with a seq_num.  This is a nscd
12712830Sdjl  * opaque 64 bit (nssuint_t) value passed with a cookie, and used to by nscd
12722830Sdjl  * to validate the sequencing of the context.  The client treats this as
12732830Sdjl  * a pass through value.
12742830Sdjl  *
12752830Sdjl  * XXX ??  Use Cookie as cross-check info so that we can detect an
12762830Sdjl  * nss_context that missed an nss_delete() or similar.
12770Sstevel@tonic-gate  */
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate struct nss_getent_context {
12800Sstevel@tonic-gate 	int			n_src;	/* >= max_src ==> end of sequence */
12810Sstevel@tonic-gate 	nss_backend_t		*be;
12820Sstevel@tonic-gate 	struct nss_db_state	*s;
12832830Sdjl 	nssuint_t		cookie;
12842830Sdjl 	nssuint_t		seq_num;
12853099Smichen 	nssuint_t		cookie_setent;
12862830Sdjl 	nss_db_params_t		param;
12870Sstevel@tonic-gate };
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate static void		nss_setent_u(nss_db_root_t *,
12900Sstevel@tonic-gate 				    nss_db_initf_t,
12910Sstevel@tonic-gate 				    nss_getent_t *);
12920Sstevel@tonic-gate static nss_status_t	nss_getent_u(nss_db_root_t *,
12930Sstevel@tonic-gate 				    nss_db_initf_t,
12940Sstevel@tonic-gate 				    nss_getent_t *,
12950Sstevel@tonic-gate 				    void *);
12960Sstevel@tonic-gate static void		nss_endent_u(nss_db_root_t *,
12970Sstevel@tonic-gate 				    nss_db_initf_t,
12980Sstevel@tonic-gate 				    nss_getent_t *);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate void
nss_setent(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)13010Sstevel@tonic-gate nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp)
13020Sstevel@tonic-gate {
13030Sstevel@tonic-gate 	if (contextpp == 0) {
13040Sstevel@tonic-gate 		return;
13050Sstevel@tonic-gate 	}
13065891Sraf 	cancel_safe_mutex_lock(&contextpp->lock);
13070Sstevel@tonic-gate 	nss_setent_u(rootp, initf, contextpp);
13085891Sraf 	cancel_safe_mutex_unlock(&contextpp->lock);
13090Sstevel@tonic-gate }
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate nss_status_t
nss_getent(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp,void * args)13120Sstevel@tonic-gate nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp,
13130Sstevel@tonic-gate 	void *args)
13140Sstevel@tonic-gate {
13150Sstevel@tonic-gate 	nss_status_t		status;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	if (contextpp == 0) {
13180Sstevel@tonic-gate 		return (NSS_UNAVAIL);
13190Sstevel@tonic-gate 	}
13205891Sraf 	cancel_safe_mutex_lock(&contextpp->lock);
13210Sstevel@tonic-gate 	status = nss_getent_u(rootp, initf, contextpp, args);
13225891Sraf 	cancel_safe_mutex_unlock(&contextpp->lock);
13230Sstevel@tonic-gate 	return (status);
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate void
nss_endent(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)13270Sstevel@tonic-gate nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp)
13280Sstevel@tonic-gate {
13290Sstevel@tonic-gate 	if (contextpp == 0) {
13300Sstevel@tonic-gate 		return;
13310Sstevel@tonic-gate 	}
13325891Sraf 	cancel_safe_mutex_lock(&contextpp->lock);
13330Sstevel@tonic-gate 	nss_endent_u(rootp, initf, contextpp);
13345891Sraf 	cancel_safe_mutex_unlock(&contextpp->lock);
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate /*
13380Sstevel@tonic-gate  * Each of the _u versions of the nss interfaces assume that the context
13392830Sdjl  * lock is held.  No need to divert to nscd.  Private to local sequencing.
13400Sstevel@tonic-gate  */
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate static void
end_iter_u(nss_db_root_t * rootp,struct nss_getent_context * contextp)13430Sstevel@tonic-gate end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp)
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate 	struct nss_db_state	*s;
13460Sstevel@tonic-gate 	nss_backend_t		*be;
13470Sstevel@tonic-gate 	int			n_src;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	s = contextp->s;
13500Sstevel@tonic-gate 	n_src = contextp->n_src;
13510Sstevel@tonic-gate 	be = contextp->be;
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	if (s != 0) {
13540Sstevel@tonic-gate 		if (n_src < s->max_src && be != 0) {
13550Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
13560Sstevel@tonic-gate 			NSS_RELOCK(&rootp, s);
13570Sstevel@tonic-gate 			nss_put_backend_u(s, n_src, be);
13580Sstevel@tonic-gate 			contextp->be = 0;  /* Should be unnecessary, but hey */
13590Sstevel@tonic-gate 			NSS_UNREF_UNLOCK(rootp, s);
13600Sstevel@tonic-gate 		}
13610Sstevel@tonic-gate 		contextp->s = 0;
13620Sstevel@tonic-gate 	}
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate static void
nss_setent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)13660Sstevel@tonic-gate nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
13670Sstevel@tonic-gate 	nss_getent_t *contextpp)
13680Sstevel@tonic-gate {
13692830Sdjl 	nss_status_t		status;
13700Sstevel@tonic-gate 	struct nss_db_state	*s;
13710Sstevel@tonic-gate 	struct nss_getent_context *contextp;
13720Sstevel@tonic-gate 	nss_backend_t		*be;
13730Sstevel@tonic-gate 	int			n_src;
13740Sstevel@tonic-gate 
13752830Sdjl 	/* setup process wide context while locked */
13760Sstevel@tonic-gate 	if ((contextp = contextpp->ctx) == 0) {
13770Sstevel@tonic-gate 		if ((contextp = libc_malloc(sizeof (*contextp))) == 0) {
13780Sstevel@tonic-gate 			return;
13790Sstevel@tonic-gate 		}
13800Sstevel@tonic-gate 		contextpp->ctx = contextp;
13812830Sdjl 		contextp->cookie = NSCD_NEW_COOKIE;	/* cookie init */
13822830Sdjl 		contextp->seq_num = 0;			/* seq_num init */
13830Sstevel@tonic-gate 		s = 0;
13840Sstevel@tonic-gate 	} else {
13850Sstevel@tonic-gate 		s = contextp->s;
13863099Smichen 		if (contextp->cookie != NSCD_LOCAL_COOKIE)
13873099Smichen 			contextp->cookie = NSCD_NEW_COOKIE;
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 
13902830Sdjl 	/* name service cache daemon divert */
13913099Smichen 	if (contextp->cookie == NSCD_NEW_COOKIE) {
13923099Smichen 		status = _nsc_setent_u(rootp, initf, contextpp);
13933099Smichen 		if (status != NSS_TRYLOCAL)
13943099Smichen 			return;
13953099Smichen 	}
13962830Sdjl 
13972830Sdjl 	/* fall through - process locally */
13980Sstevel@tonic-gate 	if (s == 0) {
13990Sstevel@tonic-gate 		NSS_LOCK_CHECK(rootp, initf, &s);
14000Sstevel@tonic-gate 		if (s == 0) {
14010Sstevel@tonic-gate 			/* Couldn't set up state, so quit */
14020Sstevel@tonic-gate 			NSS_UNLOCK(rootp);
14030Sstevel@tonic-gate 			/* ==== is there any danger of not having done an */
14040Sstevel@tonic-gate 			/* end_iter() here, and hence of losing backends? */
14050Sstevel@tonic-gate 			contextpp->ctx = 0;
14060Sstevel@tonic-gate 			libc_free(contextp);
14070Sstevel@tonic-gate 			return;
14080Sstevel@tonic-gate 		}
14090Sstevel@tonic-gate 		NSS_STATE_REF_u(s);
14100Sstevel@tonic-gate 		contextp->s = s;
14110Sstevel@tonic-gate 	} else {
14120Sstevel@tonic-gate 		s	= contextp->s;
14130Sstevel@tonic-gate 		n_src	= contextp->n_src;
14140Sstevel@tonic-gate 		be	= contextp->be;
14150Sstevel@tonic-gate 		if (n_src == 0 && be != 0) {
14160Sstevel@tonic-gate 			/*
14170Sstevel@tonic-gate 			 * Optimization:  don't do endent, don't change
14180Sstevel@tonic-gate 			 *   backends, just do the setent.  Look Ma, no locks
14190Sstevel@tonic-gate 			 *   (nor any context that needs updating).
14200Sstevel@tonic-gate 			 */
14210Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
14220Sstevel@tonic-gate 			return;
14230Sstevel@tonic-gate 		}
14240Sstevel@tonic-gate 		if (n_src < s->max_src && be != 0) {
14250Sstevel@tonic-gate 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
14260Sstevel@tonic-gate 			NSS_RELOCK(&rootp, s);
14270Sstevel@tonic-gate 			nss_put_backend_u(s, n_src, be);
14280Sstevel@tonic-gate 			contextp->be = 0;	/* Play it safe */
14290Sstevel@tonic-gate 		} else {
14300Sstevel@tonic-gate 			NSS_RELOCK(&rootp, s);
14310Sstevel@tonic-gate 		}
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 	for (n_src = 0, be = 0; n_src < s->max_src &&
14346279Sdjl 	    (be = nss_get_backend_u(&rootp, s, n_src)) == 0; n_src++) {
14350Sstevel@tonic-gate 		;
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 	NSS_UNLOCK(rootp);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	contextp->n_src	= n_src;
14400Sstevel@tonic-gate 	contextp->be	= be;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	if (be == 0) {
14430Sstevel@tonic-gate 		/* Things are broken enough that we can't do setent/getent */
14440Sstevel@tonic-gate 		nss_endent_u(rootp, initf, contextpp);
14450Sstevel@tonic-gate 		return;
14460Sstevel@tonic-gate 	}
14470Sstevel@tonic-gate 	(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate static nss_status_t
nss_getent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp,void * args)14510Sstevel@tonic-gate nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
14520Sstevel@tonic-gate 	nss_getent_t *contextpp, void *args)
14530Sstevel@tonic-gate {
14542830Sdjl 	nss_status_t		status;
14550Sstevel@tonic-gate 	struct nss_db_state	*s;
14560Sstevel@tonic-gate 	struct nss_getent_context *contextp;
14570Sstevel@tonic-gate 	int			n_src;
14580Sstevel@tonic-gate 	nss_backend_t		*be;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	if ((contextp = contextpp->ctx) == 0) {
14610Sstevel@tonic-gate 		nss_setent_u(rootp, initf, contextpp);
14620Sstevel@tonic-gate 		if ((contextp = contextpp->ctx) == 0) {
14630Sstevel@tonic-gate 			/* Give up */
14640Sstevel@tonic-gate 			return (NSS_UNAVAIL);
14650Sstevel@tonic-gate 		}
14660Sstevel@tonic-gate 	}
14672830Sdjl 	/* name service cache daemon divert */
14682830Sdjl 	status = _nsc_getent_u(rootp, initf, contextpp, args);
14692830Sdjl 	if (status != NSS_TRYLOCAL)
14702830Sdjl 		return (status);
14712830Sdjl 
14722830Sdjl 	/* fall through - process locally */
14730Sstevel@tonic-gate 	s	= contextp->s;
14740Sstevel@tonic-gate 	n_src	= contextp->n_src;
14750Sstevel@tonic-gate 	be	= contextp->be;
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	if (s == 0) {
14780Sstevel@tonic-gate 		/*
14790Sstevel@tonic-gate 		 * We've done an end_iter() and haven't done nss_setent()
14800Sstevel@tonic-gate 		 * or nss_endent() since;  we should stick in this state
14810Sstevel@tonic-gate 		 * until the caller invokes one of those two routines.
14820Sstevel@tonic-gate 		 */
14830Sstevel@tonic-gate 		return (NSS_SUCCESS);
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	while (n_src < s->max_src) {
14870Sstevel@tonic-gate 		nss_status_t res;
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 		if (be == 0) {
14900Sstevel@tonic-gate 			/* If it's null it's a bug, but let's play safe */
14910Sstevel@tonic-gate 			res = NSS_UNAVAIL;
14920Sstevel@tonic-gate 		} else {
14930Sstevel@tonic-gate 			res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args);
14940Sstevel@tonic-gate 		}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 		if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) {
14970Sstevel@tonic-gate 			if (res != __NSW_SUCCESS) {
14980Sstevel@tonic-gate 				end_iter_u(rootp, contextp);
14990Sstevel@tonic-gate 			}
15000Sstevel@tonic-gate 			return (res);
15010Sstevel@tonic-gate 		}
15020Sstevel@tonic-gate 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
15030Sstevel@tonic-gate 		NSS_RELOCK(&rootp, s);
15040Sstevel@tonic-gate 		nss_put_backend_u(s, n_src, be);
15050Sstevel@tonic-gate 		do {
15060Sstevel@tonic-gate 			n_src++;
15070Sstevel@tonic-gate 		} while (n_src < s->max_src &&
15086279Sdjl 		    (be = nss_get_backend_u(&rootp, s, n_src)) == 0);
15099575SMilan.Jurik@Sun.COM 		contextp->be = be;
15100Sstevel@tonic-gate 		if (be == 0) {
15110Sstevel@tonic-gate 			/*
15120Sstevel@tonic-gate 			 * This is the case where we failed to get the backend
15130Sstevel@tonic-gate 			 * for the last source. We exhausted all sources.
15149575SMilan.Jurik@Sun.COM 			 *
15159575SMilan.Jurik@Sun.COM 			 * We need to do cleanup ourselves because end_iter_u()
15169575SMilan.Jurik@Sun.COM 			 * does not do it for be == 0.
15170Sstevel@tonic-gate 			 */
15189575SMilan.Jurik@Sun.COM 			NSS_UNREF_UNLOCK(rootp, s);
15199575SMilan.Jurik@Sun.COM 			contextp->s = 0;
15209575SMilan.Jurik@Sun.COM 			break;
15219575SMilan.Jurik@Sun.COM 		} else {
15220Sstevel@tonic-gate 			NSS_UNLOCK(rootp);
15239575SMilan.Jurik@Sun.COM 			contextp->n_src = n_src;
15249575SMilan.Jurik@Sun.COM 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
15250Sstevel@tonic-gate 		}
15260Sstevel@tonic-gate 	}
15270Sstevel@tonic-gate 	/* Got to the end of the sources without finding another entry */
15280Sstevel@tonic-gate 	end_iter_u(rootp, contextp);
15290Sstevel@tonic-gate 	return (NSS_SUCCESS);
15300Sstevel@tonic-gate 	/* success is either a successful entry or end of the sources */
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate /*ARGSUSED*/
15340Sstevel@tonic-gate static void
nss_endent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)15350Sstevel@tonic-gate nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
15360Sstevel@tonic-gate 	nss_getent_t *contextpp)
15370Sstevel@tonic-gate {
15382830Sdjl 	nss_status_t		status;
15390Sstevel@tonic-gate 	struct nss_getent_context *contextp;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	if ((contextp = contextpp->ctx) == 0) {
15420Sstevel@tonic-gate 		/* nss_endent() on an unused context is a no-op */
15430Sstevel@tonic-gate 		return;
15440Sstevel@tonic-gate 	}
15452830Sdjl 
15462830Sdjl 	/* notify name service cache daemon */
15472830Sdjl 	status = _nsc_endent_u(rootp, initf, contextpp);
15482830Sdjl 	if (status != NSS_TRYLOCAL) {
15492830Sdjl 		/* clean up */
15502830Sdjl 		libc_free(contextp);
15512830Sdjl 		contextpp->ctx = 0;
15522830Sdjl 		return;
15532830Sdjl 	}
15542830Sdjl 
15552830Sdjl 	/* fall through - process locally */
15562830Sdjl 
15570Sstevel@tonic-gate 	/*
15580Sstevel@tonic-gate 	 * Existing code (BSD, SunOS) works in such a way that getXXXent()
15590Sstevel@tonic-gate 	 *   following an endXXXent() behaves as though the user had invoked
15600Sstevel@tonic-gate 	 *   setXXXent(), i.e. it iterates properly from the beginning.
15610Sstevel@tonic-gate 	 * We'd better not break this, so our choices are
15620Sstevel@tonic-gate 	 *	(1) leave the context structure around, and do nss_setent or
15630Sstevel@tonic-gate 	 *	    something equivalent,
15640Sstevel@tonic-gate 	 *   or	(2) free the context completely, and rely on the code in
15650Sstevel@tonic-gate 	 *	    nss_getent() that makes getXXXent() do the right thing
15660Sstevel@tonic-gate 	 *	    even without a preceding setXXXent().
15670Sstevel@tonic-gate 	 * The code below does (2), which frees up resources nicely but will
15680Sstevel@tonic-gate 	 * cost more if the user then does more getXXXent() operations.
15690Sstevel@tonic-gate 	 * Moral:  for efficiency, don't call endXXXent() prematurely.
15700Sstevel@tonic-gate 	 */
15710Sstevel@tonic-gate 	end_iter_u(rootp, contextp);
15720Sstevel@tonic-gate 	libc_free(contextp);
15730Sstevel@tonic-gate 	contextpp->ctx = 0;
15740Sstevel@tonic-gate }
15752830Sdjl 
15762830Sdjl /*
15772830Sdjl  * pack dbd data into header
15782830Sdjl  * Argment pointers assumed valid.
15792830Sdjl  * poff offset position pointer
15802830Sdjl  *   IN = starting offset for dbd header
15812830Sdjl  *   OUT = starting offset for next section
15822830Sdjl  */
15832830Sdjl 
15842830Sdjl static nss_status_t
nss_pack_dbd(void * buffer,size_t bufsize,nss_db_params_t * p,size_t * poff)15852830Sdjl nss_pack_dbd(void *buffer, size_t bufsize, nss_db_params_t *p, size_t *poff)
15862830Sdjl {
15872830Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
15882830Sdjl 	nss_dbd_t		*pdbd;
15892830Sdjl 	size_t			off = *poff;
15902830Sdjl 	size_t			len, blen;
15912830Sdjl 	size_t			n, nc, dc;
15922830Sdjl 	char			*bptr;
15932830Sdjl 
15942830Sdjl 	pbuf->dbd_off = (nssuint_t)off;
15952830Sdjl 	bptr = (char *)buffer + off;
15962830Sdjl 	blen = bufsize - off;
15972830Sdjl 	len = sizeof (nss_dbd_t);
15982830Sdjl 
15992830Sdjl 	n = nc = dc = 0;
16002830Sdjl 	if (p->name == NULL) {
16012830Sdjl 		errno = ERANGE;			/* actually EINVAL */
16022830Sdjl 		return (NSS_ERROR);
16032830Sdjl 	}
16042830Sdjl 
16052830Sdjl 	/* if default config not specified, the flag should be reset */
16062830Sdjl 	if (p->default_config == NULL) {
16072830Sdjl 		p->default_config = "<NULL>";
16082830Sdjl 		p->flags = p->flags & ~NSS_USE_DEFAULT_CONFIG;
16092830Sdjl 	}
16102830Sdjl 
16112830Sdjl 	n = strlen(p->name) + 1;
16122830Sdjl 	dc = strlen(p->default_config) + 1;
16132830Sdjl 	if (n < 2 || dc < 2) {			/* What no DB? */
16142830Sdjl 		errno = ERANGE;			/* actually EINVAL */
16152830Sdjl 		return (NSS_ERROR);
16162830Sdjl 	}
16172830Sdjl 	if (p->config_name != NULL) {
16182830Sdjl 		nc = strlen(p->config_name) + 1;
16192830Sdjl 	}
16202830Sdjl 	if ((len + n + nc + dc) >= blen) {
16212830Sdjl 		errno = ERANGE;			/* actually EINVAL */
16222830Sdjl 		return (NSS_ERROR);
16232830Sdjl 	}
16242830Sdjl 
16252830Sdjl 	pdbd = (nss_dbd_t *)((void *)bptr);
16262830Sdjl 	bptr += len;
16272830Sdjl 	pdbd->flags = p->flags;
16282830Sdjl 	pdbd->o_name = len;
16292830Sdjl 	(void) strlcpy(bptr, p->name, n);
16302830Sdjl 	len += n;
16312830Sdjl 	bptr += n;
16322830Sdjl 	if (nc == 0) {
16332830Sdjl 		pdbd->o_config_name = 0;
16342830Sdjl 	} else {
16352830Sdjl 		pdbd->o_config_name = len;
16362830Sdjl 		(void) strlcpy(bptr, p->config_name, nc);
16372830Sdjl 		bptr += nc;
16382830Sdjl 		len += nc;
16392830Sdjl 	}
16402830Sdjl 	pdbd->o_default_config = len;
16412830Sdjl 	(void) strlcpy(bptr, p->default_config, dc);
16422830Sdjl 	len += dc;
16432830Sdjl 	pbuf->dbd_len = (nssuint_t)len;
16442830Sdjl 	off += ROUND_UP(len, sizeof (nssuint_t));
16452830Sdjl 	*poff = off;
16462830Sdjl 	return (NSS_SUCCESS);
16472830Sdjl }
16482830Sdjl 
16492830Sdjl /*
16502830Sdjl  * Switch packed and _nsc (switch->nscd) interfaces
16512830Sdjl  * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND
16522830Sdjl  */
16532830Sdjl 
16542830Sdjl /*ARGSUSED*/
16552830Sdjl nss_status_t
nss_pack(void * buffer,size_t bufsize,nss_db_root_t * rootp,nss_db_initf_t initf,int search_fnum,void * search_args)16562830Sdjl nss_pack(void *buffer, size_t bufsize, nss_db_root_t *rootp,
16572830Sdjl 	    nss_db_initf_t initf, int search_fnum, void *search_args)
16582830Sdjl {
16592830Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
16602830Sdjl 	nss_XbyY_args_t		*in = (nss_XbyY_args_t *)search_args;
16612830Sdjl 	nss_db_params_t		tparam = { 0 };
16622830Sdjl 	nss_status_t		ret = NSS_ERROR;
16632830Sdjl 	const char		*dbn;
16642830Sdjl 	size_t			blen, len, off = 0;
16652830Sdjl 	char			*bptr;
16662830Sdjl 	struct nss_groupsbymem	*gbm;
16672830Sdjl 
16682830Sdjl 	if (pbuf == NULL || in == NULL || initf == (nss_db_initf_t)NULL) {
16692830Sdjl 		errno = ERANGE;			/* actually EINVAL */
16702830Sdjl 		return (ret);
16712830Sdjl 	}
16722830Sdjl 	tparam.cleanup = NULL;
16732830Sdjl 	(*initf)(&tparam);
16742830Sdjl 	if ((dbn = tparam.name) == 0) {
16752830Sdjl 		if (tparam.cleanup != 0)
16762830Sdjl 			(tparam.cleanup)(&tparam);
16772830Sdjl 		errno = ERANGE;			/* actually EINVAL */
16782830Sdjl 		return (ret);
16792830Sdjl 	}
16802830Sdjl 
16812830Sdjl 	/* init buffer header */
16822830Sdjl 	pbuf->pbufsiz = (nssuint_t)bufsize;
16832830Sdjl 	pbuf->p_ruid = (uint32_t)getuid();
16842830Sdjl 	pbuf->p_euid = (uint32_t)geteuid();
16852830Sdjl 	pbuf->p_version = NSCD_HEADER_REV;
16862830Sdjl 	pbuf->p_status = 0;
16872830Sdjl 	pbuf->p_errno = 0;
16882830Sdjl 	pbuf->p_herrno = 0;
16892830Sdjl 
16902830Sdjl 	/* possible audituser init */
16912830Sdjl 	if (strcmp(dbn, NSS_DBNAM_AUTHATTR) == 0 && in->h_errno != 0)
16922830Sdjl 		pbuf->p_herrno = (uint32_t)in->h_errno;
16932830Sdjl 
16942830Sdjl 	pbuf->libpriv = 0;
16952830Sdjl 
16962830Sdjl 	off = sizeof (nss_pheader_t);
16972830Sdjl 
16982830Sdjl 	/* setup getXbyY operation - database and sub function */
16992830Sdjl 	pbuf->nss_dbop = (uint32_t)search_fnum;
17002830Sdjl 	ret = nss_pack_dbd(buffer, bufsize, &tparam, &off);
17012830Sdjl 	if (ret != NSS_SUCCESS) {
17022830Sdjl 		errno = ERANGE;			/* actually EINVAL */
17032830Sdjl 		return (ret);
17042830Sdjl 	}
17052830Sdjl 	ret = NSS_ERROR;
17062830Sdjl 	/* setup request key */
17072830Sdjl 	pbuf->key_off = (nssuint_t)off;
17082830Sdjl 	bptr = (char *)buffer + off;
17092830Sdjl 	blen = bufsize - off;
17102830Sdjl 	/* use key2str if provided, else call default getXbyY packer */
17112830Sdjl 	if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
17122830Sdjl 		/* This has to run locally due to backend knowledge */
17132830Sdjl 		if (search_fnum == NSS_DBOP_NETGROUP_SET) {
17142830Sdjl 			errno = 0;
17152830Sdjl 			return (NSS_TRYLOCAL);
17162830Sdjl 		}
17172830Sdjl 		/* use default packer for known getXbyY ops */
17182830Sdjl 		ret = nss_default_key2str(bptr, blen, in, dbn,
17196279Sdjl 		    search_fnum, &len);
17202830Sdjl 	} else if (in->key2str == NULL ||
17216279Sdjl 	    (search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
17226279Sdjl 	    strcmp(dbn, NSS_DBNAM_GROUP) == 0)) {
17232830Sdjl 		/* use default packer for known getXbyY ops */
17242830Sdjl 		ret = nss_default_key2str(bptr, blen, in, dbn,
17256279Sdjl 		    search_fnum, &len);
17262830Sdjl 	} else {
17272830Sdjl 		ret = (*in->key2str)(bptr, blen, &in->key, &len);
17282830Sdjl 	}
17292830Sdjl 	if (tparam.cleanup != 0)
17302830Sdjl 		(tparam.cleanup)(&tparam);
17312830Sdjl 	if (ret != NSS_SUCCESS) {
17322830Sdjl 		errno = ERANGE;			/* actually ENOMEM */
17332830Sdjl 		return (ret);
17342830Sdjl 	}
17352830Sdjl 	pbuf->key_len = (nssuint_t)len;
17362830Sdjl 	off += ROUND_UP(len, sizeof (nssuint_t));
17372830Sdjl 
17382830Sdjl 	pbuf->data_off = (nssuint_t)off;
17392830Sdjl 	pbuf->data_len = (nssuint_t)(bufsize - off);
17402830Sdjl 	/*
17412830Sdjl 	 * Prime data return with first result if
17422830Sdjl 	 * the first result is passed in
17432830Sdjl 	 * [_getgroupsbymember oddness]
17442830Sdjl 	 */
17452830Sdjl 	gbm = (struct nss_groupsbymem *)search_args;
17462830Sdjl 	if (search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
17472830Sdjl 	    strcmp(dbn, NSS_DBNAM_GROUP) == 0 && gbm->numgids == 1) {
17483099Smichen 		gid_t	*gidp;
17493099Smichen 		gidp = (gid_t *)((void *)((char *)buffer + off));
17503099Smichen 		*gidp = gbm->gid_array[0];
17512830Sdjl 	}
17522830Sdjl 
17532830Sdjl 	errno = 0;				/* just in case ... */
17542830Sdjl 	return (NSS_SUCCESS);
17552830Sdjl }
17562830Sdjl 
17572830Sdjl /*
17582830Sdjl  * Switch packed and _nsc (switch->nscd) {set/get/end}ent interfaces
17592830Sdjl  * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND
17602830Sdjl  */
17612830Sdjl 
17622830Sdjl /*ARGSUSED*/
17632830Sdjl nss_status_t
nss_pack_ent(void * buffer,size_t bufsize,nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)17642830Sdjl nss_pack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp,
17652830Sdjl 	    nss_db_initf_t initf, nss_getent_t *contextpp)
17662830Sdjl {
17672830Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
17682830Sdjl 	struct nss_getent_context *contextp = contextpp->ctx;
17692830Sdjl 	nss_status_t		ret = NSS_ERROR;
17702830Sdjl 	size_t			blen, len = 0, off = 0;
17712830Sdjl 	char			*bptr;
17722830Sdjl 	nssuint_t		*nptr;
17732830Sdjl 
17742830Sdjl 	if (pbuf == NULL || initf == (nss_db_initf_t)NULL) {
17752830Sdjl 		errno = ERANGE;			/* actually EINVAL */
17762830Sdjl 		return (ret);
17772830Sdjl 	}
17782830Sdjl 
17792830Sdjl 	/* init buffer header */
17802830Sdjl 	pbuf->pbufsiz = (nssuint_t)bufsize;
17812830Sdjl 	pbuf->p_ruid = (uint32_t)getuid();
17822830Sdjl 	pbuf->p_euid = (uint32_t)geteuid();
17832830Sdjl 	pbuf->p_version = NSCD_HEADER_REV;
17842830Sdjl 	pbuf->p_status = 0;
17852830Sdjl 	pbuf->p_errno = 0;
17862830Sdjl 	pbuf->p_herrno = 0;
17872830Sdjl 	pbuf->libpriv = 0;
17882830Sdjl 
17892830Sdjl 	off = sizeof (nss_pheader_t);
17902830Sdjl 
17912830Sdjl 	/* setup getXXXent operation - database and sub function */
17922830Sdjl 	pbuf->nss_dbop = (uint32_t)0;	/* iterators have no dbop */
17932830Sdjl 	ret = nss_pack_dbd(buffer, bufsize, &contextp->param, &off);
17942830Sdjl 	if (ret != NSS_SUCCESS) {
17952830Sdjl 		errno = ERANGE;			/* actually EINVAL */
17962830Sdjl 		return (ret);
17972830Sdjl 	}
17982830Sdjl 	ret = NSS_ERROR;
17992830Sdjl 	off += ROUND_UP(len, sizeof (nssuint_t));
18002830Sdjl 
18012830Sdjl 	pbuf->key_off = (nssuint_t)off;
18022830Sdjl 	bptr = (char *)buffer + off;
18032830Sdjl 	blen = bufsize - off;
18042830Sdjl 	len = (size_t)(sizeof (nssuint_t) * 2);
18052830Sdjl 	if (len >= blen) {
18062830Sdjl 		errno = ERANGE;			/* actually EINVAL */
18072830Sdjl 		return (ret);
18082830Sdjl 	}
18092830Sdjl 	nptr = (nssuint_t *)((void *)bptr);
18102830Sdjl 	*nptr++ = contextp->cookie;
18112830Sdjl 	*nptr = contextp->seq_num;
18122830Sdjl 	pbuf->key_len = (nssuint_t)len;
18132830Sdjl 
18142830Sdjl 	off += len;
18152830Sdjl 	pbuf->data_off = (nssuint_t)off;
18162830Sdjl 	pbuf->data_len = (nssuint_t)(bufsize - off);
18172830Sdjl 	return (NSS_SUCCESS);
18182830Sdjl }
18192830Sdjl 
18202830Sdjl /*
18212830Sdjl  * Unpack packed arguments buffer
18222830Sdjl  * Return: status, errnos and results from requested operation.
18232830Sdjl  *
18242830Sdjl  * NOTES: When getgroupsbymember is being processed in the NSCD backend,
18252830Sdjl  * or via the backwards compatibility interfaces then the standard
18262830Sdjl  * str2group API is used in conjunction with process_cstr.  When,
18272830Sdjl  * processing a returned buffer, in NSS2 the return results are the
18282830Sdjl  * already digested groups array.  Therefore, unpack the digested results
18292830Sdjl  * back to the return buffer.
18302830Sdjl  *
18312830Sdjl  * Note: the digested results are nssuint_t quantities.  _getgroupsbymember
18322830Sdjl  * digests int quantities.  Therefore convert.  Assume input is in nssuint_t
18332830Sdjl  * quantities.  Store in an int array... Assume gid's are <= 32 bits...
18342830Sdjl  */
18352830Sdjl 
18362830Sdjl /*ARGSUSED*/
18372830Sdjl nss_status_t
nss_unpack(void * buffer,size_t bufsize,nss_db_root_t * rootp,nss_db_initf_t initf,int search_fnum,void * search_args)18382830Sdjl nss_unpack(void *buffer, size_t bufsize, nss_db_root_t *rootp,
18392830Sdjl 	    nss_db_initf_t initf, int search_fnum, void *search_args)
18402830Sdjl {
18412830Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
18422830Sdjl 	nss_XbyY_args_t		*in = (nss_XbyY_args_t *)search_args;
18432830Sdjl 	nss_dbd_t		*pdbd;
18442830Sdjl 	char			*dbn;
18452830Sdjl 	nss_status_t		status;
18462830Sdjl 	char			*buf;
18472830Sdjl 	int			len;
18482830Sdjl 	int			ret;
18492830Sdjl 	int			i;
18503015Schinlong 	int			fmt_type;
18512830Sdjl 	gid_t			*gidp;
18523099Smichen 	gid_t			*gptr;
18532830Sdjl 	struct nss_groupsbymem	*arg;
18542830Sdjl 
18552830Sdjl 
18562830Sdjl 	if (pbuf == NULL || in == NULL)
18572830Sdjl 		return (-1);
18582830Sdjl 	status = pbuf->p_status;
18593015Schinlong 	/* Identify odd cases */
18603015Schinlong 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
18613015Schinlong 	dbn = (char *)pdbd + pdbd->o_name;
18623015Schinlong 	fmt_type = 0; /* nss_XbyY_args_t */
18633015Schinlong 	if (search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
18646279Sdjl 	    strcmp(dbn, NSS_DBNAM_GROUP) == 0)
18653015Schinlong 		fmt_type = 1; /* struct nss_groupsbymem */
18663015Schinlong 	else if (search_fnum == NSS_DBOP_NETGROUP_IN &&
18676279Sdjl 	    strcmp(dbn, NSS_DBNAM_NETGROUP) == 0)
18683015Schinlong 		fmt_type = 2; /* struct nss_innetgr_args */
18693015Schinlong 
18702830Sdjl 	/* if error - door's switch error */
18712830Sdjl 	/* extended data could contain additional information? */
18722830Sdjl 	if (status != NSS_SUCCESS) {
18733015Schinlong 		if (fmt_type == 0) {
18743015Schinlong 			in->h_errno = (int)pbuf->p_herrno;
18753015Schinlong 			if (pbuf->p_errno == ERANGE)
18763015Schinlong 				in->erange = 1;
18773015Schinlong 		}
18782830Sdjl 		return (status);
18792830Sdjl 	}
18802830Sdjl 
18812830Sdjl 	if (pbuf->data_off == 0 || pbuf->data_len == 0)
18822830Sdjl 		return (NSS_NOTFOUND);
18832830Sdjl 
18842830Sdjl 	buf = (char *)buffer + pbuf->data_off;
18852830Sdjl 	len = pbuf->data_len;
18862830Sdjl 
18872830Sdjl 	/* sidestep odd cases */
18883015Schinlong 	if (fmt_type == 1) {
18893015Schinlong 		arg = (struct nss_groupsbymem *)in;
18903015Schinlong 		/* copy returned gid array from returned nscd buffer */
18913099Smichen 		i = len / sizeof (gid_t);
18923015Schinlong 		/* not enough buffer */
18933015Schinlong 		if (i > arg->maxgids) {
18943015Schinlong 			i = arg->maxgids;
18953015Schinlong 		}
18963015Schinlong 		arg->numgids = i;
18973015Schinlong 		gidp = arg->gid_array;
18983099Smichen 		gptr = (gid_t *)((void *)buf);
1899*11411SSurya.Prakki@Sun.COM 		(void) memcpy(gidp, gptr, len);
19003015Schinlong 		return (NSS_SUCCESS);
19013015Schinlong 	}
19023015Schinlong 	if (fmt_type == 2) {
19033015Schinlong 		struct nss_innetgr_args *arg = (struct nss_innetgr_args *)in;
19043015Schinlong 
19053015Schinlong 		if (pbuf->p_status == NSS_SUCCESS) {
19063015Schinlong 			arg->status = NSS_NETGR_FOUND;
19072830Sdjl 			return (NSS_SUCCESS);
19083015Schinlong 		} else {
19093015Schinlong 			arg->status = NSS_NETGR_NO;
19103015Schinlong 			return (NSS_NOTFOUND);
19112830Sdjl 		}
19122830Sdjl 	}
19132830Sdjl 
19142830Sdjl 	/* process the normal cases */
19152830Sdjl 	/* marshall data directly into users buffer */
19162830Sdjl 	ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer,
19176279Sdjl 	    in->buf.buflen);
19182830Sdjl 	if (ret == NSS_STR_PARSE_ERANGE) {
19192830Sdjl 		in->returnval = 0;
19202830Sdjl 		in->returnlen = 0;
19212830Sdjl 		in->erange    = 1;
19222830Sdjl 		ret = NSS_NOTFOUND;
19232830Sdjl 	} else if (ret == NSS_STR_PARSE_SUCCESS) {
19242830Sdjl 		in->returnval = in->buf.result;
19252830Sdjl 		in->returnlen =  len;
19262830Sdjl 		ret = NSS_SUCCESS;
19272830Sdjl 	}
19282830Sdjl 	in->h_errno = (int)pbuf->p_herrno;
19292830Sdjl 	return ((nss_status_t)ret);
19302830Sdjl }
19312830Sdjl 
19322830Sdjl /*
19332830Sdjl  * Unpack a returned packed {set,get,end}ent arguments buffer
19342830Sdjl  * Return: status, errnos, cookie info and results from requested operation.
19352830Sdjl  */
19362830Sdjl 
19372830Sdjl /*ARGSUSED*/
19382830Sdjl nss_status_t
nss_unpack_ent(void * buffer,size_t bufsize,nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp,void * args)19392830Sdjl nss_unpack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp,
19402830Sdjl 	    nss_db_initf_t initf, nss_getent_t *contextpp, void *args)
19412830Sdjl {
19422830Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
19432830Sdjl 	nss_XbyY_args_t		*in = (nss_XbyY_args_t *)args;
19442830Sdjl 	struct nss_getent_context *contextp = contextpp->ctx;
19452830Sdjl 	nssuint_t		*nptr;
19462830Sdjl 	nssuint_t		cookie;
19472830Sdjl 	nss_status_t		status;
19482830Sdjl 	char			*buf;
19492830Sdjl 	int			len;
19502830Sdjl 	int			ret;
19512830Sdjl 
19522830Sdjl 	if (pbuf == NULL)
19532830Sdjl 		return (-1);
19542830Sdjl 	status = pbuf->p_status;
19552830Sdjl 	/* if error - door's switch error */
19562830Sdjl 	/* extended data could contain additional information? */
19572830Sdjl 	if (status != NSS_SUCCESS)
19582830Sdjl 		return (status);
19592830Sdjl 
19602830Sdjl 	/* unpack assigned cookie from SET/GET/END request */
19612830Sdjl 	if (pbuf->key_off == 0 ||
19622830Sdjl 	    pbuf->key_len != (sizeof (nssuint_t) * 2))
19632830Sdjl 		return (NSS_NOTFOUND);
19642830Sdjl 
19652830Sdjl 	nptr = (nssuint_t *)((void *)((char *)buffer + pbuf->key_off));
19662830Sdjl 	cookie = contextp->cookie;
19673099Smichen 	if (cookie != NSCD_NEW_COOKIE && cookie != contextp->cookie_setent &&
19686279Sdjl 	    cookie != *nptr) {
19693099Smichen 		/*
19703099Smichen 		 * Should either be new, or the cookie returned by the last
19713099Smichen 		 * setent (i.e., this is the first getent after the setent)
19723099Smichen 		 * or a match, else error
19733099Smichen 		 */
19742830Sdjl 		return (NSS_NOTFOUND);
19752830Sdjl 	}
19762830Sdjl 	/* save away for the next ent request */
19772830Sdjl 	contextp->cookie = *nptr++;
19782830Sdjl 	contextp->seq_num = *nptr;
19792830Sdjl 
19802830Sdjl 	/* All done if no marshalling is expected {set,end}ent */
19812830Sdjl 	if (args == NULL)
19822830Sdjl 		return (NSS_SUCCESS);
19832830Sdjl 
19842830Sdjl 	/* unmarshall the data */
19852830Sdjl 	if (pbuf->data_off == 0 || pbuf->data_len == 0)
19862830Sdjl 		return (NSS_NOTFOUND);
19872830Sdjl 	buf = (char *)buffer + pbuf->data_off;
19882830Sdjl 
19892830Sdjl 	len = pbuf->data_len;
19902830Sdjl 
19912830Sdjl 	/* marshall data directly into users buffer */
19922830Sdjl 	ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer,
19936279Sdjl 	    in->buf.buflen);
19942830Sdjl 	if (ret == NSS_STR_PARSE_ERANGE) {
19952830Sdjl 		in->returnval = 0;
19962830Sdjl 		in->returnlen = 0;
19972830Sdjl 		in->erange    = 1;
19982830Sdjl 	} else if (ret == NSS_STR_PARSE_SUCCESS) {
19992830Sdjl 		in->returnval = in->buf.result;
20002830Sdjl 		in->returnlen =  len;
20012830Sdjl 	}
20022830Sdjl 	in->h_errno = (int)pbuf->p_herrno;
20032830Sdjl 	return ((nss_status_t)ret);
20042830Sdjl }
20052830Sdjl 
20062830Sdjl /*
20072830Sdjl  * Start of _nsc_{search|setent_u|getent_u|endent_u} NSCD interposition funcs
20082830Sdjl  */
20092830Sdjl 
20102830Sdjl nss_status_t
_nsc_search(nss_db_root_t * rootp,nss_db_initf_t initf,int search_fnum,void * search_args)20112830Sdjl _nsc_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
20122830Sdjl 	void *search_args)
20132830Sdjl {
20142830Sdjl 	nss_pheader_t		*pbuf;
20152830Sdjl 	void			*doorptr = NULL;
20162830Sdjl 	size_t			bufsize = 0;
20172830Sdjl 	size_t			datasize = 0;
20182830Sdjl 	nss_status_t		status;
20192830Sdjl 
20202830Sdjl 	if (_nsc_proc_is_cache() > 0) {
20212830Sdjl 		/* internal nscd call - don't use the door */
20222830Sdjl 		return (NSS_TRYLOCAL);
20232830Sdjl 	}
20242830Sdjl 
20252830Sdjl 	/* standard client calls nscd code */
20262830Sdjl 	if (search_args == NULL)
20272830Sdjl 		return (NSS_NOTFOUND);
20282830Sdjl 
20292830Sdjl 	/* get the door buffer  & configured size */
20302830Sdjl 	bufsize = ((nss_XbyY_args_t *)search_args)->buf.buflen;
20312830Sdjl 	if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
20322830Sdjl 		return (NSS_TRYLOCAL);
20332830Sdjl 	if (doorptr == NULL || bufsize == 0)
20342830Sdjl 		return (NSS_TRYLOCAL);
20352830Sdjl 
20362830Sdjl 	pbuf = (nss_pheader_t *)doorptr;
20372830Sdjl 	/* pack argument and request into door buffer */
20382830Sdjl 	pbuf->nsc_callnumber = NSCD_SEARCH;
20392830Sdjl 	/* copy relevant door request info into door buffer */
20402830Sdjl 	status = nss_pack((void *)pbuf, bufsize, rootp,
20416279Sdjl 	    initf, search_fnum, search_args);
20422830Sdjl 
20432830Sdjl 	/* Packing error return error results */
20442830Sdjl 	if (status != NSS_SUCCESS)
20452830Sdjl 		return (status);
20462830Sdjl 
20472830Sdjl 	/* transfer packed switch request to nscd via door */
20482830Sdjl 	/* data_off can be used because it is header+dbd_len+key_len */
20492830Sdjl 	datasize = pbuf->data_off;
20502830Sdjl 	status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
20512830Sdjl 
20522830Sdjl 	/* If unsuccessful fallback to standard nss logic */
20532830Sdjl 	if (status != NSS_SUCCESS) {
20542830Sdjl 		/*
20552830Sdjl 		 * check if doors reallocated the memory underneath us
20562830Sdjl 		 * if they did munmap it or suffer a memory leak
20572830Sdjl 		 */
20582830Sdjl 		if (doorptr != (void *)pbuf) {
20592830Sdjl 			_nsc_resizedoorbuf(bufsize);
20609170SRoger.Faulkner@Sun.COM 			(void) munmap((void *)doorptr, bufsize);
20612830Sdjl 		}
20622830Sdjl 		return (NSS_TRYLOCAL);
20632830Sdjl 	}
20642830Sdjl 
20652830Sdjl 	/* unpack and marshall data/errors to user structure */
20662830Sdjl 	/* set any error conditions */
20672830Sdjl 	status = nss_unpack((void *)doorptr, bufsize, rootp, initf,
20686279Sdjl 	    search_fnum, search_args);
20692830Sdjl 	/*
20702830Sdjl 	 * check if doors reallocated the memory underneath us
20712830Sdjl 	 * if they did munmap it or suffer a memory leak
20722830Sdjl 	 */
20732830Sdjl 	if (doorptr != (void *)pbuf) {
20742830Sdjl 		_nsc_resizedoorbuf(bufsize);
20759170SRoger.Faulkner@Sun.COM 		(void) munmap((void *)doorptr, bufsize);
20762830Sdjl 	}
20772830Sdjl 	return (status);
20782830Sdjl }
20792830Sdjl 
20802830Sdjl /*
20812830Sdjl  * contact nscd for a cookie or to reset an existing cookie
20822830Sdjl  * if nscd fails (NSS_TRYLOCAL) then set cookie to -1 and
20832830Sdjl  * continue diverting to local
20842830Sdjl  */
20852830Sdjl nss_status_t
_nsc_setent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)20862830Sdjl _nsc_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
20872830Sdjl 	nss_getent_t *contextpp)
20882830Sdjl {
20892830Sdjl 	nss_status_t		status = NSS_TRYLOCAL;
20902830Sdjl 	struct nss_getent_context *contextp = contextpp->ctx;
20912830Sdjl 	nss_pheader_t		*pbuf;
20922830Sdjl 	void			*doorptr = NULL;
20932830Sdjl 	size_t			bufsize = 0;
20942830Sdjl 	size_t			datasize = 0;
20952830Sdjl 
20962830Sdjl 	/* return if already in local mode */
20972830Sdjl 	if (contextp->cookie == NSCD_LOCAL_COOKIE)
20982830Sdjl 		return (NSS_TRYLOCAL);
20992830Sdjl 
21002830Sdjl 	if (_nsc_proc_is_cache() > 0) {
21012830Sdjl 		/* internal nscd call - don't try to use the door */
21022830Sdjl 		contextp->cookie = NSCD_LOCAL_COOKIE;
21032830Sdjl 		return (NSS_TRYLOCAL);
21042830Sdjl 	}
21052830Sdjl 
21062830Sdjl 	/* get the door buffer & configured size */
21072830Sdjl 	if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) {
21082830Sdjl 		contextp->cookie = NSCD_LOCAL_COOKIE;
21092830Sdjl 		return (NSS_TRYLOCAL);
21102830Sdjl 	}
21112830Sdjl 	if (doorptr == NULL || bufsize == 0) {
21122830Sdjl 		contextp->cookie = NSCD_LOCAL_COOKIE;
21132830Sdjl 		return (NSS_TRYLOCAL);
21142830Sdjl 	}
21152830Sdjl 
21162830Sdjl 	pbuf = (nss_pheader_t *)doorptr;
21172830Sdjl 	pbuf->nsc_callnumber = NSCD_SETENT;
21182830Sdjl 
21192830Sdjl 	contextp->param.cleanup = NULL;
21202830Sdjl 	(*initf)(&contextp->param);
21212830Sdjl 	if (contextp->param.name == 0) {
21222830Sdjl 		if (contextp->param.cleanup != 0)
21232830Sdjl 			(contextp->param.cleanup)(&contextp->param);
21242830Sdjl 		errno = ERANGE;			/* actually EINVAL */
21252830Sdjl 		return (NSS_ERROR);
21262830Sdjl 	}
21272830Sdjl 
21282830Sdjl 	/* pack relevant setent request info into door buffer */
21296279Sdjl 	status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
21302830Sdjl 	if (status != NSS_SUCCESS)
21312830Sdjl 		return (status);
21322830Sdjl 
21332830Sdjl 	/* transfer packed switch request to nscd via door */
21342830Sdjl 	/* data_off can be used because it is header+dbd_len+key_len */
21352830Sdjl 	datasize = pbuf->data_off;
21362830Sdjl 	status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
21372830Sdjl 
21382830Sdjl 	/* If fallback to standard nss logic (door failure) if possible */
21392830Sdjl 	if (status != NSS_SUCCESS) {
21402830Sdjl 		if (contextp->cookie == NSCD_NEW_COOKIE) {
21412830Sdjl 			contextp->cookie = NSCD_LOCAL_COOKIE;
21422830Sdjl 			return (NSS_TRYLOCAL);
21432830Sdjl 		}
21442830Sdjl 		return (NSS_UNAVAIL);
21452830Sdjl 	}
21462830Sdjl 	/* unpack returned cookie stash it away */
21472830Sdjl 	status = nss_unpack_ent((void *)doorptr, bufsize, rootp,
21486279Sdjl 	    initf, contextpp, NULL);
21493099Smichen 	/* save the setent cookie for later use */
21503099Smichen 	contextp->cookie_setent = contextp->cookie;
21512830Sdjl 	/*
21522830Sdjl 	 * check if doors reallocated the memory underneath us
21532830Sdjl 	 * if they did munmap it or suffer a memory leak
21542830Sdjl 	 */
21552830Sdjl 	if (doorptr != (void *)pbuf) {
21562830Sdjl 		_nsc_resizedoorbuf(bufsize);
21579170SRoger.Faulkner@Sun.COM 		(void) munmap((void *)doorptr, bufsize);
21582830Sdjl 	}
21592830Sdjl 	return (status);
21602830Sdjl }
21612830Sdjl 
21622830Sdjl nss_status_t
_nsc_getent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp,void * args)21632830Sdjl _nsc_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
21642830Sdjl 	nss_getent_t *contextpp, void *args)
21652830Sdjl {
21662830Sdjl 	nss_status_t		status = NSS_TRYLOCAL;
21672830Sdjl 	struct nss_getent_context *contextp = contextpp->ctx;
21682830Sdjl 	nss_pheader_t		*pbuf;
21692830Sdjl 	void			*doorptr = NULL;
21702830Sdjl 	size_t			bufsize = 0;
21712830Sdjl 	size_t			datasize = 0;
21722830Sdjl 
21732830Sdjl 	/* return if already in local mode */
21742830Sdjl 	if (contextp->cookie == NSCD_LOCAL_COOKIE)
21752830Sdjl 		return (NSS_TRYLOCAL);
21762830Sdjl 
21772830Sdjl 	/* _nsc_setent_u already checked for nscd local case ... proceed */
21782830Sdjl 	if (args == NULL)
21792830Sdjl 		return (NSS_NOTFOUND);
21802830Sdjl 
21812830Sdjl 	/* get the door buffer  & configured size */
21822830Sdjl 	bufsize = ((nss_XbyY_args_t *)args)->buf.buflen;
21832830Sdjl 	if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
21842830Sdjl 		return (NSS_UNAVAIL);
21852830Sdjl 	if (doorptr == NULL || bufsize == 0)
21862830Sdjl 		return (NSS_UNAVAIL);
21872830Sdjl 
21882830Sdjl 	pbuf = (nss_pheader_t *)doorptr;
21892830Sdjl 	pbuf->nsc_callnumber = NSCD_GETENT;
21902830Sdjl 
21912830Sdjl 	/* pack relevant setent request info into door buffer */
21926279Sdjl 	status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
21932830Sdjl 	if (status != NSS_SUCCESS)
21942830Sdjl 		return (status);
21952830Sdjl 
21962830Sdjl 	/* transfer packed switch request to nscd via door */
21972830Sdjl 	/* data_off can be used because it is header+dbd_len+key_len */
21982830Sdjl 	datasize = pbuf->data_off;
21992830Sdjl 	status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
22002830Sdjl 
22012830Sdjl 	/* If fallback to standard nss logic (door failure) if possible */
22022830Sdjl 	if (status != NSS_SUCCESS) {
22033099Smichen 		if (status == NSS_TRYLOCAL ||
22046279Sdjl 		    contextp->cookie == NSCD_NEW_COOKIE) {
22052830Sdjl 			contextp->cookie = NSCD_LOCAL_COOKIE;
22063099Smichen 
22073099Smichen 			/* init the local cookie */
22083099Smichen 			nss_setent_u(rootp, initf, contextpp);
22093099Smichen 			if (contextpp->ctx == 0)
22103099Smichen 				return (NSS_UNAVAIL);
22112830Sdjl 			return (NSS_TRYLOCAL);
22122830Sdjl 		}
22132830Sdjl 		return (NSS_UNAVAIL);
22142830Sdjl 	}
22152830Sdjl 	/* check error, unpack and process results */
22162830Sdjl 	status = nss_unpack_ent((void *)doorptr, bufsize, rootp,
22176279Sdjl 	    initf, contextpp, args);
22182830Sdjl 	/*
22192830Sdjl 	 * check if doors reallocated the memory underneath us
22202830Sdjl 	 * if they did munmap it or suffer a memory leak
22212830Sdjl 	 */
22222830Sdjl 	if (doorptr != (void *)pbuf) {
22232830Sdjl 		_nsc_resizedoorbuf(bufsize);
22249170SRoger.Faulkner@Sun.COM 		(void) munmap((void *)doorptr, bufsize);
22252830Sdjl 	}
22262830Sdjl 	return (status);
22272830Sdjl }
22282830Sdjl 
22292830Sdjl nss_status_t
_nsc_endent_u(nss_db_root_t * rootp,nss_db_initf_t initf,nss_getent_t * contextpp)22302830Sdjl _nsc_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
22312830Sdjl 	nss_getent_t *contextpp)
22322830Sdjl {
22332830Sdjl 	nss_status_t		status = NSS_TRYLOCAL;
22342830Sdjl 	struct nss_getent_context *contextp = contextpp->ctx;
22352830Sdjl 	nss_pheader_t		*pbuf;
22362830Sdjl 	void			*doorptr = NULL;
22372830Sdjl 	size_t			bufsize = 0;
22382830Sdjl 	size_t			datasize = 0;
22392830Sdjl 
22402830Sdjl 	/* return if already in local mode */
22412830Sdjl 	if (contextp->cookie == NSCD_LOCAL_COOKIE)
22422830Sdjl 		return (NSS_TRYLOCAL);
22432830Sdjl 
22442830Sdjl 	/* _nsc_setent_u already checked for nscd local case ... proceed */
22452830Sdjl 
22462830Sdjl 	/* get the door buffer  & configured size */
22472830Sdjl 	if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
22482830Sdjl 		return (NSS_UNAVAIL);
22492830Sdjl 	if (doorptr == NULL || bufsize == 0)
22502830Sdjl 		return (NSS_UNAVAIL);
22512830Sdjl 
22522830Sdjl 	/* pack up a NSCD_ENDGET request passing in the cookie */
22532830Sdjl 	pbuf = (nss_pheader_t *)doorptr;
22542830Sdjl 	pbuf->nsc_callnumber = NSCD_ENDENT;
22552830Sdjl 
22562830Sdjl 	/* pack relevant setent request info into door buffer */
22576279Sdjl 	status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
22582830Sdjl 	if (status != NSS_SUCCESS)
22592830Sdjl 		return (status);
22602830Sdjl 
22612830Sdjl 	/* transfer packed switch request to nscd via door */
22622830Sdjl 	/* data_off can be used because it is header+dbd_len+key_len */
22632830Sdjl 	datasize = pbuf->data_off;
22642830Sdjl 	(void) _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
22652830Sdjl 
22662830Sdjl 	/* error codes & unpacking ret values don't matter.  We're done */
22672830Sdjl 
22682830Sdjl 	/*
22692830Sdjl 	 * check if doors reallocated the memory underneath us
22702830Sdjl 	 * if they did munmap it or suffer a memory leak
22712830Sdjl 	 */
22722830Sdjl 	if (doorptr != (void *)pbuf) {
22732830Sdjl 		_nsc_resizedoorbuf(bufsize);
22749170SRoger.Faulkner@Sun.COM 		(void) munmap((void *)doorptr, bufsize);
22752830Sdjl 	}
22762830Sdjl 
22772830Sdjl 	/* clean up initf setup */
22782830Sdjl 	if (contextp->param.cleanup != 0)
22792830Sdjl 		(contextp->param.cleanup)(&contextp->param);
22802830Sdjl 	contextp->param.cleanup = NULL;
22812830Sdjl 
22822830Sdjl 	/* clear cookie */
22832830Sdjl 	contextp->cookie = NSCD_NEW_COOKIE;
22842830Sdjl 	return (NSS_SUCCESS);
22852830Sdjl }
22866279Sdjl 
22876279Sdjl /*
22886279Sdjl  * Internal private API to return default suggested buffer sizes
22896279Sdjl  * for nsswitch API requests
22906279Sdjl  */
22916279Sdjl 
22926279Sdjl size_t
_nss_get_bufsizes(int arg)22936279Sdjl _nss_get_bufsizes(int arg)
22946279Sdjl {
22956279Sdjl 	switch (arg) {
22966279Sdjl 	case _SC_GETGR_R_SIZE_MAX:
22976279Sdjl 		return (__nss_buflen_group);
22986279Sdjl 	}
22996279Sdjl 	return (__nss_buflen_default);
23006279Sdjl }
2301