xref: /titanic_54/usr/src/cmd/nscd/nscd_switch.c (revision cb5caa98562cf06753163f558cbcfe30b8f4673a)
1*cb5caa98Sdjl /*
2*cb5caa98Sdjl  * CDDL HEADER START
3*cb5caa98Sdjl  *
4*cb5caa98Sdjl  * The contents of this file are subject to the terms of the
5*cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6*cb5caa98Sdjl  * You may not use this file except in compliance with the License.
7*cb5caa98Sdjl  *
8*cb5caa98Sdjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*cb5caa98Sdjl  * or http://www.opensolaris.org/os/licensing.
10*cb5caa98Sdjl  * See the License for the specific language governing permissions
11*cb5caa98Sdjl  * and limitations under the License.
12*cb5caa98Sdjl  *
13*cb5caa98Sdjl  * When distributing Covered Code, include this CDDL HEADER in each
14*cb5caa98Sdjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*cb5caa98Sdjl  * If applicable, add the following below this CDDL HEADER, with the
16*cb5caa98Sdjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*cb5caa98Sdjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*cb5caa98Sdjl  *
19*cb5caa98Sdjl  * CDDL HEADER END
20*cb5caa98Sdjl  */
21*cb5caa98Sdjl /*
22*cb5caa98Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*cb5caa98Sdjl  * Use is subject to license terms.
24*cb5caa98Sdjl  */
25*cb5caa98Sdjl 
26*cb5caa98Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*cb5caa98Sdjl 
28*cb5caa98Sdjl #include <stdlib.h>	/* getenv() */
29*cb5caa98Sdjl #include <assert.h>
30*cb5caa98Sdjl #include <unistd.h>
31*cb5caa98Sdjl #include <string.h>
32*cb5caa98Sdjl #include <dlfcn.h>
33*cb5caa98Sdjl #include <nss_dbdefs.h>
34*cb5caa98Sdjl #include <exec_attr.h>
35*cb5caa98Sdjl #include <gssapi/gssapi.h>
36*cb5caa98Sdjl #include "nscd_door.h"
37*cb5caa98Sdjl #include "nscd_switch.h"
38*cb5caa98Sdjl #include "nscd_log.h"
39*cb5caa98Sdjl #include "nscd_frontend.h"
40*cb5caa98Sdjl 
41*cb5caa98Sdjl #pragma weak nss_search = _nss_search
42*cb5caa98Sdjl #define	nss_search	_nss_search
43*cb5caa98Sdjl 
44*cb5caa98Sdjl extern rwlock_t nscd_smf_service_state_lock;
45*cb5caa98Sdjl 
46*cb5caa98Sdjl /* nscd id: main, forker, or child */
47*cb5caa98Sdjl extern int _whoami;
48*cb5caa98Sdjl 
49*cb5caa98Sdjl static int
50*cb5caa98Sdjl retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp)
51*cb5caa98Sdjl {
52*cb5caa98Sdjl 	if (res != NSS_TRYAGAIN && res !=  NSS_NISSERVDNS_TRYAGAIN) {
53*cb5caa98Sdjl 		if (res == NSS_SUCCESS) {
54*cb5caa98Sdjl 			__NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]);
55*cb5caa98Sdjl 			__NSW_UNPAUSE_ACTION(
56*cb5caa98Sdjl 				lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]);
57*cb5caa98Sdjl 		}
58*cb5caa98Sdjl 		return (0);
59*cb5caa98Sdjl 	}
60*cb5caa98Sdjl 
61*cb5caa98Sdjl 	if ((res == NSS_TRYAGAIN &&
62*cb5caa98Sdjl 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) ||
63*cb5caa98Sdjl 	    (res == NSS_NISSERVDNS_TRYAGAIN &&
64*cb5caa98Sdjl 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER))
65*cb5caa98Sdjl 		return (1);
66*cb5caa98Sdjl 
67*cb5caa98Sdjl 	if (res == NSS_TRYAGAIN &&
68*cb5caa98Sdjl 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
69*cb5caa98Sdjl 		if (n <= lkp->max_retries)
70*cb5caa98Sdjl 			return (1);
71*cb5caa98Sdjl 		else {
72*cb5caa98Sdjl 			lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED;
73*cb5caa98Sdjl 			return (0);
74*cb5caa98Sdjl 		}
75*cb5caa98Sdjl 
76*cb5caa98Sdjl 	if (res == NSS_NISSERVDNS_TRYAGAIN &&
77*cb5caa98Sdjl 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
78*cb5caa98Sdjl 		if (n <= lkp->max_retries)
79*cb5caa98Sdjl 			return (1);
80*cb5caa98Sdjl 		else {
81*cb5caa98Sdjl 			lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] =
82*cb5caa98Sdjl 			    __NSW_TRYAGAIN_PAUSED;
83*cb5caa98Sdjl 			return (0);
84*cb5caa98Sdjl 		}
85*cb5caa98Sdjl 
86*cb5caa98Sdjl 	return (0);
87*cb5caa98Sdjl }
88*cb5caa98Sdjl 
89*cb5caa98Sdjl static thread_key_t loopback_key;
90*cb5caa98Sdjl static mutex_t loopback_key_lock = DEFAULTMUTEX;
91*cb5caa98Sdjl static int loopback_key_created = 0;
92*cb5caa98Sdjl typedef struct lb_key {
93*cb5caa98Sdjl 	int		srci;
94*cb5caa98Sdjl 	int		dbi;
95*cb5caa98Sdjl 	int		fnum;
96*cb5caa98Sdjl 	int		*lb_flagp;
97*cb5caa98Sdjl } lb_key_t;
98*cb5caa98Sdjl 
99*cb5caa98Sdjl static int
100*cb5caa98Sdjl set_loopback_key(lb_key_t *key) {
101*cb5caa98Sdjl 
102*cb5caa98Sdjl 	int		rc = 0;
103*cb5caa98Sdjl 	lb_key_t	*k;
104*cb5caa98Sdjl 
105*cb5caa98Sdjl 	if (!loopback_key_created) {
106*cb5caa98Sdjl 		(void) mutex_lock(&loopback_key_lock);
107*cb5caa98Sdjl 		if (!loopback_key_created) {
108*cb5caa98Sdjl 			if ((rc = thr_keycreate(&loopback_key,
109*cb5caa98Sdjl 					NULL)) == 0)
110*cb5caa98Sdjl 				loopback_key_created = 1;
111*cb5caa98Sdjl 		}
112*cb5caa98Sdjl 		(void) mutex_unlock(&loopback_key_lock);
113*cb5caa98Sdjl 	}
114*cb5caa98Sdjl 	if (rc == 0) {
115*cb5caa98Sdjl 		/* set key if not already set */
116*cb5caa98Sdjl 		if (thr_getspecific(loopback_key, (void **)&k) == 0 &&
117*cb5caa98Sdjl 				k == NULL) {
118*cb5caa98Sdjl 			rc = thr_setspecific(loopback_key, key);
119*cb5caa98Sdjl 		}
120*cb5caa98Sdjl 	}
121*cb5caa98Sdjl 
122*cb5caa98Sdjl 	return (rc);
123*cb5caa98Sdjl }
124*cb5caa98Sdjl 
125*cb5caa98Sdjl static lb_key_t *
126*cb5caa98Sdjl get_loopback_key(void) {
127*cb5caa98Sdjl 
128*cb5caa98Sdjl 	char		*me = "get_loopback_key";
129*cb5caa98Sdjl 	int 		rc = 0;
130*cb5caa98Sdjl 	lb_key_t	*k = NULL;
131*cb5caa98Sdjl 
132*cb5caa98Sdjl 	if (!loopback_key_created)
133*cb5caa98Sdjl 		return (NULL);
134*cb5caa98Sdjl 
135*cb5caa98Sdjl 	rc = thr_getspecific(loopback_key, (void **)&k);
136*cb5caa98Sdjl 
137*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
138*cb5caa98Sdjl 	(me, "get loopback key rc= %d, key = %p\n", rc, k);
139*cb5caa98Sdjl 
140*cb5caa98Sdjl 	if (rc == 0 && k != NULL)
141*cb5caa98Sdjl 		return (k);
142*cb5caa98Sdjl 
143*cb5caa98Sdjl 	return (NULL);
144*cb5caa98Sdjl }
145*cb5caa98Sdjl 
146*cb5caa98Sdjl static void
147*cb5caa98Sdjl clear_loopback_key(lb_key_t *key) {
148*cb5caa98Sdjl 
149*cb5caa98Sdjl 	char		*me = "clear_loopback_key";
150*cb5caa98Sdjl 
151*cb5caa98Sdjl 	if (loopback_key_created && key != 0) {
152*cb5caa98Sdjl 		/*
153*cb5caa98Sdjl 		 * key->lb_flagp points to the location of the
154*cb5caa98Sdjl 		 * flag, check_flag, in the stack where it was
155*cb5caa98Sdjl 		 * first set; clearing the flag tells that
156*cb5caa98Sdjl 		 * stack the loopback error has been resolved
157*cb5caa98Sdjl 		 */
158*cb5caa98Sdjl 		*key->lb_flagp = 0;
159*cb5caa98Sdjl 		(void) thr_setspecific(loopback_key, NULL);
160*cb5caa98Sdjl 	}
161*cb5caa98Sdjl 
162*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
163*cb5caa98Sdjl 	(me, "key %p cleared\n", key);
164*cb5caa98Sdjl }
165*cb5caa98Sdjl 
166*cb5caa98Sdjl static thread_key_t initf_key;
167*cb5caa98Sdjl static mutex_t initf_key_lock = DEFAULTMUTEX;
168*cb5caa98Sdjl static int initf_key_created = 0;
169*cb5caa98Sdjl 
170*cb5caa98Sdjl static int
171*cb5caa98Sdjl set_initf_key(void *pbuf) {
172*cb5caa98Sdjl 
173*cb5caa98Sdjl 	int		rc = 0;
174*cb5caa98Sdjl 
175*cb5caa98Sdjl 	if (!initf_key_created) {
176*cb5caa98Sdjl 		(void) mutex_lock(&initf_key_lock);
177*cb5caa98Sdjl 		if (!initf_key_created) {
178*cb5caa98Sdjl 			if ((rc = thr_keycreate(&initf_key, NULL)) == 0)
179*cb5caa98Sdjl 				initf_key_created = 1;
180*cb5caa98Sdjl 		}
181*cb5caa98Sdjl 		(void) mutex_unlock(&initf_key_lock);
182*cb5caa98Sdjl 	}
183*cb5caa98Sdjl 	if (rc == 0)
184*cb5caa98Sdjl 		rc = thr_setspecific(initf_key, pbuf);
185*cb5caa98Sdjl 
186*cb5caa98Sdjl 	return (rc);
187*cb5caa98Sdjl }
188*cb5caa98Sdjl 
189*cb5caa98Sdjl static void *
190*cb5caa98Sdjl get_initf_key(void) {
191*cb5caa98Sdjl 
192*cb5caa98Sdjl 	char		*me = "get_initf_key";
193*cb5caa98Sdjl 	void		*pbuf;
194*cb5caa98Sdjl 	int 		rc = 0;
195*cb5caa98Sdjl 
196*cb5caa98Sdjl 	if (!initf_key_created)
197*cb5caa98Sdjl 		return (NULL);
198*cb5caa98Sdjl 
199*cb5caa98Sdjl 	rc = thr_getspecific(initf_key, (void **)&pbuf);
200*cb5caa98Sdjl 
201*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
202*cb5caa98Sdjl 	(me, "got initf pbuf rc= %d, key = %p\n", rc, pbuf);
203*cb5caa98Sdjl 
204*cb5caa98Sdjl 	if (rc == 0 && pbuf != NULL)
205*cb5caa98Sdjl 		return (pbuf);
206*cb5caa98Sdjl 
207*cb5caa98Sdjl 	return (NULL);
208*cb5caa98Sdjl }
209*cb5caa98Sdjl 
210*cb5caa98Sdjl static void
211*cb5caa98Sdjl clear_initf_key(void) {
212*cb5caa98Sdjl 
213*cb5caa98Sdjl 	char		*me = "clear_initf_key";
214*cb5caa98Sdjl 
215*cb5caa98Sdjl 	if (initf_key_created)
216*cb5caa98Sdjl 		(void) thr_setspecific(initf_key, NULL);
217*cb5caa98Sdjl 
218*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
219*cb5caa98Sdjl 	(me, "initf pbuf cleared\n");
220*cb5caa98Sdjl }
221*cb5caa98Sdjl 
222*cb5caa98Sdjl /*
223*cb5caa98Sdjl  * Call the input initf function to extract the
224*cb5caa98Sdjl  * NSS front end parameters and examine them to
225*cb5caa98Sdjl  * determine if an NSS lookup is to be performed
226*cb5caa98Sdjl  * on a regular or a pseudo (called from compat
227*cb5caa98Sdjl  * backend) database. Then set the necessary
228*cb5caa98Sdjl  * parameters for later data structures creation
229*cb5caa98Sdjl  * and processing.
230*cb5caa98Sdjl  */
231*cb5caa98Sdjl static nscd_rc_t
232*cb5caa98Sdjl getparams(
233*cb5caa98Sdjl 	int			search_fnum,
234*cb5caa98Sdjl 	nss_db_initf_t		initf,
235*cb5caa98Sdjl 	nscd_nsw_params_t	*params)
236*cb5caa98Sdjl {
237*cb5caa98Sdjl 
238*cb5caa98Sdjl 	nscd_rc_t	rc = NSCD_SUCCESS;
239*cb5caa98Sdjl 	nss_db_params_t	*p;
240*cb5caa98Sdjl 	int		j;
241*cb5caa98Sdjl 	char		*dbn;
242*cb5caa98Sdjl 	const char	*n;
243*cb5caa98Sdjl 
244*cb5caa98Sdjl 	p = &params->p;
245*cb5caa98Sdjl 	(void) memset(p, 0, sizeof (*p));
246*cb5caa98Sdjl 	(*initf)(p);
247*cb5caa98Sdjl 	params->dbi = -1;
248*cb5caa98Sdjl 	params->cfgdbi = -1;
249*cb5caa98Sdjl 	params->compati = -1;
250*cb5caa98Sdjl 	params->dnsi = -1;
251*cb5caa98Sdjl 
252*cb5caa98Sdjl 	/* map database name to index */
253*cb5caa98Sdjl 	n = p->name;
254*cb5caa98Sdjl 	for (j = 0; j < NSCD_NUM_DB; j++) {
255*cb5caa98Sdjl 		dbn = NSCD_NSW_DB_NAME(j);
256*cb5caa98Sdjl 		if (*n != *dbn)
257*cb5caa98Sdjl 			continue;
258*cb5caa98Sdjl 		if (strcmp(n, dbn) == 0) {
259*cb5caa98Sdjl 			params->dbi = j;
260*cb5caa98Sdjl 			if (*n != 'h' && *n != 'i' && *n != 's' && *n != 'a')
261*cb5caa98Sdjl 				break;
262*cb5caa98Sdjl 			if (strcmp(n, NSS_DBNAM_HOSTS) == 0 &&
263*cb5caa98Sdjl 				search_fnum == NSS_DBOP_HOSTS_BYNAME)
264*cb5caa98Sdjl 				params->dnsi = 0;
265*cb5caa98Sdjl 			else if (strcmp(n, NSS_DBNAM_IPNODES) == 0 &&
266*cb5caa98Sdjl 				search_fnum == NSS_DBOP_IPNODES_BYNAME)
267*cb5caa98Sdjl 				params->dnsi = 1;
268*cb5caa98Sdjl 			else if (strcmp(n, NSS_DBNAM_SHADOW) == 0)
269*cb5caa98Sdjl 				params->privdb = 1;
270*cb5caa98Sdjl 			else if (strcmp(n, NSS_DBNAM_AUDITUSER) == 0)
271*cb5caa98Sdjl 				params->privdb = 1;
272*cb5caa98Sdjl 			break;
273*cb5caa98Sdjl 		}
274*cb5caa98Sdjl 	}
275*cb5caa98Sdjl 
276*cb5caa98Sdjl 	/*
277*cb5caa98Sdjl 	 * use the switch policy for passwd_compat or
278*cb5caa98Sdjl 	 * group_compat?
279*cb5caa98Sdjl 	 */
280*cb5caa98Sdjl 	if (p->config_name != NULL) {
281*cb5caa98Sdjl 
282*cb5caa98Sdjl 		n = p->config_name;
283*cb5caa98Sdjl 		for (j = 0; j < NSCD_NUM_DB; j++) {
284*cb5caa98Sdjl 			dbn = NSCD_NSW_DB_NAME(j);
285*cb5caa98Sdjl 			if (*n == *dbn) {
286*cb5caa98Sdjl 				if (strcmp(n, dbn) == 0) {
287*cb5caa98Sdjl 					params->cfgdbi = j;
288*cb5caa98Sdjl 					break;
289*cb5caa98Sdjl 				}
290*cb5caa98Sdjl 			}
291*cb5caa98Sdjl 		}
292*cb5caa98Sdjl 	}
293*cb5caa98Sdjl 
294*cb5caa98Sdjl 	/* map the database name to the pseudo database index */
295*cb5caa98Sdjl 	if (params->cfgdbi != -1) {
296*cb5caa98Sdjl 		if (strstr(p->config_name, "_compat") != NULL) {
297*cb5caa98Sdjl 			n = p->name;
298*cb5caa98Sdjl 			for (j = params->cfgdbi; j < NSCD_NUM_DB; j++) {
299*cb5caa98Sdjl 				dbn = NSCD_NSW_DB_NAME(j);
300*cb5caa98Sdjl 				if (*n == *dbn) {
301*cb5caa98Sdjl 					if (strcmp(n, dbn) == 0) {
302*cb5caa98Sdjl 						params->compati = j;
303*cb5caa98Sdjl 						break;
304*cb5caa98Sdjl 					}
305*cb5caa98Sdjl 				}
306*cb5caa98Sdjl 			}
307*cb5caa98Sdjl 		}
308*cb5caa98Sdjl 	}
309*cb5caa98Sdjl 
310*cb5caa98Sdjl 	assert(params->dbi != -1);
311*cb5caa98Sdjl 	return (rc);
312*cb5caa98Sdjl }
313*cb5caa98Sdjl 
314*cb5caa98Sdjl static void
315*cb5caa98Sdjl nscd_initf(nss_db_params_t	*p)
316*cb5caa98Sdjl {
317*cb5caa98Sdjl 	nss_pheader_t		*pbuf;
318*cb5caa98Sdjl 	nssuint_t		off;
319*cb5caa98Sdjl 	nss_dbd_t		*pdbd;
320*cb5caa98Sdjl 	char			*me = "nscd_initf";
321*cb5caa98Sdjl 
322*cb5caa98Sdjl 	pbuf = (nss_pheader_t *)get_initf_key();
323*cb5caa98Sdjl 	if (pbuf == NULL) {
324*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
325*cb5caa98Sdjl 		(me, "ERROR: initf key not set\n");
326*cb5caa98Sdjl 		return;
327*cb5caa98Sdjl 	}
328*cb5caa98Sdjl 
329*cb5caa98Sdjl 	if (pbuf->dbd_len <= sizeof (nss_dbd_t)) {
330*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
331*cb5caa98Sdjl 		(me, "invalid db front params data ? dbd_len = %d\n",
332*cb5caa98Sdjl 		pbuf->dbd_len);
333*cb5caa98Sdjl 		return;
334*cb5caa98Sdjl 	}
335*cb5caa98Sdjl 
336*cb5caa98Sdjl 	off = pbuf->dbd_off;
337*cb5caa98Sdjl 	pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off));
338*cb5caa98Sdjl 
339*cb5caa98Sdjl 	p->name = (char *)pdbd + pdbd->o_name;
340*cb5caa98Sdjl 	p->config_name = (char *)pdbd + pdbd->o_config_name;
341*cb5caa98Sdjl 	p->default_config = (char *)pdbd + pdbd->o_default_config;
342*cb5caa98Sdjl 	p->flags = (enum nss_dbp_flags)pdbd->flags;
343*cb5caa98Sdjl 	(void) memcpy(&p->private, &pbuf->nscdpriv, sizeof (p->private));
344*cb5caa98Sdjl 
345*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
346*cb5caa98Sdjl 	(me, "db frontend params: name =%s, config_name = %s, "
347*cb5caa98Sdjl 	"default_config = %s, flags = %x\n", p->name,
348*cb5caa98Sdjl 	(p->config_name && *p->config_name != '\0' ?
349*cb5caa98Sdjl 				p->config_name : "<NOT SPECIFIED>"),
350*cb5caa98Sdjl 	(p->default_config && *p->default_config != '\0' ?
351*cb5caa98Sdjl 				p->default_config : "<NOT SPECIFIED>"),
352*cb5caa98Sdjl 	p->flags);
353*cb5caa98Sdjl }
354*cb5caa98Sdjl 
355*cb5caa98Sdjl 
356*cb5caa98Sdjl static void
357*cb5caa98Sdjl trace_result(
358*cb5caa98Sdjl 	int		dbi,
359*cb5caa98Sdjl 	int		srci,
360*cb5caa98Sdjl 	int		op,
361*cb5caa98Sdjl 	nss_status_t	res,
362*cb5caa98Sdjl 	nss_XbyY_args_t	*arg)
363*cb5caa98Sdjl {
364*cb5caa98Sdjl 	char	*res_str;
365*cb5caa98Sdjl 	char	*src = "?";
366*cb5caa98Sdjl 	char	*db = "?";
367*cb5caa98Sdjl 	char	*me = "nss_search";
368*cb5caa98Sdjl 
369*cb5caa98Sdjl 	switch (res) {
370*cb5caa98Sdjl 	case NSS_SUCCESS:
371*cb5caa98Sdjl 		res_str = "NSS_SUCCESS";
372*cb5caa98Sdjl 		break;
373*cb5caa98Sdjl 	case NSS_NOTFOUND:
374*cb5caa98Sdjl 		res_str = "NSS_NOTFOUND";
375*cb5caa98Sdjl 		break;
376*cb5caa98Sdjl 	case NSS_UNAVAIL:
377*cb5caa98Sdjl 		res_str = "NSS_UNAVAIL";
378*cb5caa98Sdjl 		break;
379*cb5caa98Sdjl 	case NSS_TRYAGAIN:
380*cb5caa98Sdjl 		res_str = "NSS_TRYAGAIN";
381*cb5caa98Sdjl 		break;
382*cb5caa98Sdjl 	case NSS_NISSERVDNS_TRYAGAIN:
383*cb5caa98Sdjl 		res_str = "NSS_NISSERVDNS_TRYAGAIN";
384*cb5caa98Sdjl 		break;
385*cb5caa98Sdjl 	default:
386*cb5caa98Sdjl 		res_str = "UNKNOWN STATUS";
387*cb5caa98Sdjl 		break;
388*cb5caa98Sdjl 	}
389*cb5caa98Sdjl 
390*cb5caa98Sdjl 	if (dbi != -1)
391*cb5caa98Sdjl 		db = NSCD_NSW_DB_NAME(dbi);
392*cb5caa98Sdjl 	if (srci != -1)
393*cb5caa98Sdjl 		src = NSCD_NSW_SRC_NAME(srci);
394*cb5caa98Sdjl 
395*cb5caa98Sdjl 	if (res == NSS_SUCCESS) {
396*cb5caa98Sdjl 		_nscd_logit(me,
397*cb5caa98Sdjl "%s: database: %s, operation: %d, source: %s returned \"%s\", length = %d\n",
398*cb5caa98Sdjl 		res_str, db, op, src, arg->buf.buffer, arg->returnlen);
399*cb5caa98Sdjl 
400*cb5caa98Sdjl 		return;
401*cb5caa98Sdjl 	}
402*cb5caa98Sdjl 
403*cb5caa98Sdjl 	_nscd_logit(me,
404*cb5caa98Sdjl "%s: database: %s, operation: %d, source: %s, erange= %d, errno: %s \n",
405*cb5caa98Sdjl 		res_str, db, op, src, arg->erange, strerror(arg->h_errno));
406*cb5caa98Sdjl }
407*cb5caa98Sdjl 
408*cb5caa98Sdjl /*
409*cb5caa98Sdjl  * Determine if a request should be done locally in the getXbyY caller's
410*cb5caa98Sdjl  * process. Return none zero if yes, 0 otherwise.
411*cb5caa98Sdjl  * This function returnis 1 if:
412*cb5caa98Sdjl  *   -- the database is exec_attr and the search_flag is GET_ALL
413*cb5caa98Sdjl  */
414*cb5caa98Sdjl static int
415*cb5caa98Sdjl try_local(
416*cb5caa98Sdjl 	int			dbi,
417*cb5caa98Sdjl 	void			*arg)
418*cb5caa98Sdjl {
419*cb5caa98Sdjl 	struct nss_XbyY_args	*ap = (struct nss_XbyY_args *)arg;
420*cb5caa98Sdjl 	_priv_execattr		*ep;
421*cb5caa98Sdjl 	int			rc = 0;
422*cb5caa98Sdjl 	char			*me = "try_local";
423*cb5caa98Sdjl 
424*cb5caa98Sdjl 	if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_EXECATTR) == 0) {
425*cb5caa98Sdjl 		if ((ep = ap->key.attrp) != NULL &&
426*cb5caa98Sdjl 				ep->search_flag == GET_ALL)
427*cb5caa98Sdjl 			rc = 1;
428*cb5caa98Sdjl 	}
429*cb5caa98Sdjl 
430*cb5caa98Sdjl 	if (rc != 0) {
431*cb5caa98Sdjl 
432*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
433*cb5caa98Sdjl 		(me, "TRYLOCAL: exec_attr:GET_ALL\n");
434*cb5caa98Sdjl 	}
435*cb5caa98Sdjl 
436*cb5caa98Sdjl 	return (rc);
437*cb5caa98Sdjl }
438*cb5caa98Sdjl 
439*cb5caa98Sdjl static nscd_rc_t
440*cb5caa98Sdjl get_dns_funcs(int dnsi, void **func_p)
441*cb5caa98Sdjl {
442*cb5caa98Sdjl 	char		*me = "get_dns_funcs";
443*cb5caa98Sdjl 	static void	*handle = NULL;
444*cb5caa98Sdjl 	static mutex_t	func_lock = DEFAULTMUTEX;
445*cb5caa98Sdjl 	void		*sym;
446*cb5caa98Sdjl 	char		*func_name[2] = { "_nss_get_dns_hosts_name",
447*cb5caa98Sdjl 				"_nss_get_dns_ipnodes_name" };
448*cb5caa98Sdjl 	static void	*func[2] = {NULL, NULL};
449*cb5caa98Sdjl 
450*cb5caa98Sdjl 	if (handle != NULL && dnsi > 0 && func[dnsi] != NULL) {
451*cb5caa98Sdjl 		(void) memcpy(func_p, &func[dnsi], sizeof (void *));
452*cb5caa98Sdjl 		return (NSCD_SUCCESS);
453*cb5caa98Sdjl 	}
454*cb5caa98Sdjl 
455*cb5caa98Sdjl 	(void) mutex_lock(&func_lock);
456*cb5caa98Sdjl 
457*cb5caa98Sdjl 	/* close the handle if requested */
458*cb5caa98Sdjl 	if (dnsi < 0) {
459*cb5caa98Sdjl 		if (handle != NULL) {
460*cb5caa98Sdjl 			(void) dlclose(handle);
461*cb5caa98Sdjl 			func[0] = NULL;
462*cb5caa98Sdjl 			func[1] = NULL;
463*cb5caa98Sdjl 		}
464*cb5caa98Sdjl 		(void) mutex_unlock(&func_lock);
465*cb5caa98Sdjl 		return (NSCD_SUCCESS);
466*cb5caa98Sdjl 	}
467*cb5caa98Sdjl 
468*cb5caa98Sdjl 	if (handle != NULL && func[dnsi] != NULL) {
469*cb5caa98Sdjl 		(void) memcpy(func_p, &func[dnsi], sizeof (void *));
470*cb5caa98Sdjl 		(void) mutex_unlock(&func_lock);
471*cb5caa98Sdjl 		return (NSCD_SUCCESS);
472*cb5caa98Sdjl 	}
473*cb5caa98Sdjl 
474*cb5caa98Sdjl 	if (handle == NULL) {
475*cb5caa98Sdjl 		handle = dlopen("nss_dns.so.1", RTLD_LAZY);
476*cb5caa98Sdjl 		if (handle == NULL) {
477*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
478*cb5caa98Sdjl 				NSCD_LOG_LEVEL_ERROR)
479*cb5caa98Sdjl 			(me, "unable to dlopen nss_dns.so.1\n");
480*cb5caa98Sdjl 			(void) mutex_unlock(&func_lock);
481*cb5caa98Sdjl 			return (NSCD_CFG_DLOPEN_ERROR);
482*cb5caa98Sdjl 		}
483*cb5caa98Sdjl 	}
484*cb5caa98Sdjl 
485*cb5caa98Sdjl 	if ((sym = dlsym(handle, func_name[dnsi])) == NULL) {
486*cb5caa98Sdjl 
487*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR)
488*cb5caa98Sdjl 		(me, "unable to find symbol %s\n", func_name[dnsi]);
489*cb5caa98Sdjl 		(void) mutex_unlock(&func_lock);
490*cb5caa98Sdjl 		return (NSCD_CFG_DLSYM_ERROR);
491*cb5caa98Sdjl 	} else {
492*cb5caa98Sdjl 		(void) memcpy(func_p, &sym, sizeof (void *));
493*cb5caa98Sdjl 		(void) memcpy(&func[dnsi], &sym, sizeof (void *));
494*cb5caa98Sdjl 	}
495*cb5caa98Sdjl 
496*cb5caa98Sdjl 	(void) mutex_unlock(&func_lock);
497*cb5caa98Sdjl 	return (NSCD_SUCCESS);
498*cb5caa98Sdjl }
499*cb5caa98Sdjl 
500*cb5caa98Sdjl static nss_status_t
501*cb5caa98Sdjl search_dns_withttl(nscd_sw_return_t *swret, char *srcname, int dnsi)
502*cb5caa98Sdjl {
503*cb5caa98Sdjl 	nss_status_t	(*func)();
504*cb5caa98Sdjl 	nss_status_t	res = NSS_UNAVAIL;
505*cb5caa98Sdjl 	nscd_rc_t	rc;
506*cb5caa98Sdjl 
507*cb5caa98Sdjl 	swret->noarg = 0;
508*cb5caa98Sdjl 	if (strcmp(srcname, "dns") != 0)
509*cb5caa98Sdjl 		return (NSS_ERROR);
510*cb5caa98Sdjl 
511*cb5caa98Sdjl 	rc = get_dns_funcs(dnsi, (void **)&func);
512*cb5caa98Sdjl 	if (rc == NSCD_SUCCESS)
513*cb5caa98Sdjl 		res = (func)(NULL, &swret->pbuf, &swret->pbufsiz);
514*cb5caa98Sdjl 	return (res);
515*cb5caa98Sdjl }
516*cb5caa98Sdjl 
517*cb5caa98Sdjl /*
518*cb5caa98Sdjl  * Returns a flag to indicate if needs to fall back to the
519*cb5caa98Sdjl  * main nscd when a per-user lookup failed with rc NSS_NOTFOUND.
520*cb5caa98Sdjl  */
521*cb5caa98Sdjl static int
522*cb5caa98Sdjl set_fallback_flag(char *srcname, nss_status_t rc)
523*cb5caa98Sdjl {
524*cb5caa98Sdjl 	char	*me = "set_fallback_flag";
525*cb5caa98Sdjl 	if (strcmp(srcname, "ldap") == 0 && rc == NSS_NOTFOUND) {
526*cb5caa98Sdjl 
527*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
528*cb5caa98Sdjl 		(me, "NSS_NOTFOUND (ldap): fallback to main nscd "
529*cb5caa98Sdjl 		"may be needed\n");
530*cb5caa98Sdjl 		return (1);
531*cb5caa98Sdjl 	}
532*cb5caa98Sdjl 	return (0);
533*cb5caa98Sdjl }
534*cb5caa98Sdjl 
535*cb5caa98Sdjl nss_status_t
536*cb5caa98Sdjl nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
537*cb5caa98Sdjl 	void *search_args)
538*cb5caa98Sdjl {
539*cb5caa98Sdjl 	char			*me = "nss_search";
540*cb5caa98Sdjl 	nss_status_t		res = NSS_UNAVAIL;
541*cb5caa98Sdjl 	nscd_nsw_state_t	*s = NULL;
542*cb5caa98Sdjl 	int			n_src;
543*cb5caa98Sdjl 	unsigned int		status_vec = 0;
544*cb5caa98Sdjl 	int			dbi, srci = -1;
545*cb5caa98Sdjl 	int			check_loopback = 0;
546*cb5caa98Sdjl 	int			state_thr = 0;
547*cb5caa98Sdjl 	lb_key_t		key, *k = NULL;
548*cb5caa98Sdjl 	nss_db_root_t		root_db;
549*cb5caa98Sdjl 	nscd_nsw_params_t	params;
550*cb5caa98Sdjl 	nscd_sw_return_t	*swret;
551*cb5caa98Sdjl 
552*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
553*cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, search_fnum = %d, "
554*cb5caa98Sdjl 		"search_args = %p\n", rootp, initf,
555*cb5caa98Sdjl 		search_fnum, search_args);
556*cb5caa98Sdjl 
557*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_received_g++;
558*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g++;
559*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_queued_g++;
560*cb5caa98Sdjl 
561*cb5caa98Sdjl 	/* determine db index, cfg db index, etc */
562*cb5caa98Sdjl 	(void) getparams(search_fnum, initf, &params);
563*cb5caa98Sdjl 	dbi = params.dbi;
564*cb5caa98Sdjl 
565*cb5caa98Sdjl 	/* get address of the switch engine return data area */
566*cb5caa98Sdjl 	if (initf == nscd_initf) {
567*cb5caa98Sdjl 		swret = (nscd_sw_return_t *)params.p.private;
568*cb5caa98Sdjl 		swret->srci = -1;
569*cb5caa98Sdjl 	} else {
570*cb5caa98Sdjl 		swret = NULL;
571*cb5caa98Sdjl 		params.dnsi = -1;
572*cb5caa98Sdjl 	}
573*cb5caa98Sdjl 
574*cb5caa98Sdjl 	/*
575*cb5caa98Sdjl 	 * for request that should be processed by the client,
576*cb5caa98Sdjl 	 * send it back with status NSS_TRYLOCAL
577*cb5caa98Sdjl 	 */
578*cb5caa98Sdjl 	if (try_local(dbi, search_args) == 1) {
579*cb5caa98Sdjl 		res = NSS_TRYLOCAL;
580*cb5caa98Sdjl 		goto error_exit;
581*cb5caa98Sdjl 	}
582*cb5caa98Sdjl 
583*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_received++;
584*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress++;
585*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_queued++;
586*cb5caa98Sdjl 
587*cb5caa98Sdjl 	/* if lookup not enabled, return NSS_UNAVAIL  */
588*cb5caa98Sdjl 	if (!(NSCD_SW_CFG_G.enable_lookup_g == nscd_true &&
589*cb5caa98Sdjl 		NSCD_SW_CFG(dbi).enable_lookup == nscd_true)) {
590*cb5caa98Sdjl 
591*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
592*cb5caa98Sdjl 		(me, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi));
593*cb5caa98Sdjl 
594*cb5caa98Sdjl 		goto error_exit;
595*cb5caa98Sdjl 	}
596*cb5caa98Sdjl 
597*cb5caa98Sdjl 	/* determine if loopback checking is configured */
598*cb5caa98Sdjl 	if (NSCD_SW_CFG_G.enable_loopback_checking_g == nscd_true &&
599*cb5caa98Sdjl 		NSCD_SW_CFG(dbi).enable_loopback_checking == nscd_true) {
600*cb5caa98Sdjl 		check_loopback = 1;
601*cb5caa98Sdjl 
602*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
603*cb5caa98Sdjl 		(me, "loopback checking enabled for %s\n",
604*cb5caa98Sdjl 		NSCD_NSW_DB_NAME(dbi));
605*cb5caa98Sdjl 	}
606*cb5caa98Sdjl 
607*cb5caa98Sdjl 	if (check_loopback) {
608*cb5caa98Sdjl 		k = get_loopback_key();
609*cb5caa98Sdjl 		if (k != NULL) {
610*cb5caa98Sdjl 			if (k->dbi != dbi || k->fnum != search_fnum) {
611*cb5caa98Sdjl 				clear_loopback_key(k);
612*cb5caa98Sdjl 				k = NULL;
613*cb5caa98Sdjl 			}
614*cb5caa98Sdjl 		}
615*cb5caa98Sdjl 	}
616*cb5caa98Sdjl 
617*cb5caa98Sdjl 	if (s == 0) {
618*cb5caa98Sdjl 		nscd_rc_t	rc;
619*cb5caa98Sdjl 
620*cb5caa98Sdjl 		if (check_loopback) {
621*cb5caa98Sdjl 			rc = _nscd_get_nsw_state_thread(&root_db, &params);
622*cb5caa98Sdjl 			state_thr = 1;
623*cb5caa98Sdjl 		} else
624*cb5caa98Sdjl 			rc = _nscd_get_nsw_state(&root_db, &params);
625*cb5caa98Sdjl 
626*cb5caa98Sdjl 		NSCD_SW_STATS_G.lookup_request_queued_g--;
627*cb5caa98Sdjl 		NSCD_SW_STATS(dbi).lookup_request_queued--;
628*cb5caa98Sdjl 
629*cb5caa98Sdjl 		if (rc != NSCD_SUCCESS)
630*cb5caa98Sdjl 				goto error_exit;
631*cb5caa98Sdjl 
632*cb5caa98Sdjl 		s = (nscd_nsw_state_t *)root_db.s;
633*cb5caa98Sdjl 	}
634*cb5caa98Sdjl 
635*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
636*cb5caa98Sdjl 	(me, "database = %s, config = [ %s ]\n", NSCD_NSW_DB_NAME(dbi),
637*cb5caa98Sdjl 	(*s->nsw_cfg_p)->nsw_cfg_str);
638*cb5caa98Sdjl 
639*cb5caa98Sdjl 	for (n_src = 0;  n_src < s->max_src;  n_src++) {
640*cb5caa98Sdjl 		nss_backend_t		*be;
641*cb5caa98Sdjl 		nss_backend_op_t	funcp;
642*cb5caa98Sdjl 		struct __nsw_lookup_v1	*lkp;
643*cb5caa98Sdjl 		int			smf_state;
644*cb5caa98Sdjl 		int			n_loop = 0;
645*cb5caa98Sdjl 		int			max_retry = 10;
646*cb5caa98Sdjl 
647*cb5caa98Sdjl 		res = NSS_UNAVAIL;
648*cb5caa98Sdjl 
649*cb5caa98Sdjl 		if (n_src == 0)
650*cb5caa98Sdjl 			lkp = s->config->lookups;
651*cb5caa98Sdjl 		else
652*cb5caa98Sdjl 			lkp = lkp->next;
653*cb5caa98Sdjl 
654*cb5caa98Sdjl 		/* set the number of max. retries */
655*cb5caa98Sdjl 		if (lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
656*cb5caa98Sdjl 			max_retry = lkp->max_retries;
657*cb5caa98Sdjl 
658*cb5caa98Sdjl 		srci = (*s->nsw_cfg_p)->src_idx[n_src];
659*cb5caa98Sdjl 		if (swret != NULL)
660*cb5caa98Sdjl 			swret->srci = srci;
661*cb5caa98Sdjl 
662*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
663*cb5caa98Sdjl 		(me, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci));
664*cb5caa98Sdjl 
665*cb5caa98Sdjl 		/* if no privilege to look up, skip */
666*cb5caa98Sdjl 		if (params.privdb == 1 && swret != NULL &&
667*cb5caa98Sdjl 			strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 &&
668*cb5caa98Sdjl 			_nscd_get_client_euid() != 0) {
669*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
670*cb5caa98Sdjl 				NSCD_LOG_LEVEL_DEBUG)
671*cb5caa98Sdjl 			(me, "no privilege to look up, skip source\n");
672*cb5caa98Sdjl 
673*cb5caa98Sdjl 			goto next_src;
674*cb5caa98Sdjl 		}
675*cb5caa98Sdjl 
676*cb5caa98Sdjl 		/* get state of the (backend) client service */
677*cb5caa98Sdjl 		smf_state = _nscd_get_smf_state(srci, dbi, 0);
678*cb5caa98Sdjl 
679*cb5caa98Sdjl 		/* stop if the source is one that should be TRYLOCAL */
680*cb5caa98Sdjl 		if (smf_state == NSCD_SVC_STATE_UNKNOWN_SRC) {
681*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
682*cb5caa98Sdjl 					NSCD_LOG_LEVEL_DEBUG)
683*cb5caa98Sdjl 			(me, "returning TRYLOCAL ... \n");
684*cb5caa98Sdjl 			res = NSS_TRYLOCAL;
685*cb5caa98Sdjl 			goto free_nsw_state;
686*cb5caa98Sdjl 		}
687*cb5caa98Sdjl 
688*cb5caa98Sdjl 		if (check_loopback && k != NULL) {
689*cb5caa98Sdjl 
690*cb5caa98Sdjl 			if (k->srci == srci && k->dbi == dbi)
691*cb5caa98Sdjl 				if (k->fnum == search_fnum) {
692*cb5caa98Sdjl 
693*cb5caa98Sdjl 					_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
694*cb5caa98Sdjl 						NSCD_LOG_LEVEL_DEBUG)
695*cb5caa98Sdjl 					(me, "loopback detected: "
696*cb5caa98Sdjl 					"source = %s, database = %s "
697*cb5caa98Sdjl 					"search fnum = %d\n",
698*cb5caa98Sdjl 					NSCD_NSW_SRC_NAME(srci),
699*cb5caa98Sdjl 					NSCD_NSW_DB_NAME(dbi), search_fnum);
700*cb5caa98Sdjl 
701*cb5caa98Sdjl 				NSCD_SW_STATS_G.loopback_nsw_db_skipped_g++;
702*cb5caa98Sdjl 				NSCD_SW_STATS(dbi).loopback_nsw_db_skipped++;
703*cb5caa98Sdjl 					continue;
704*cb5caa98Sdjl 				}
705*cb5caa98Sdjl 		}
706*cb5caa98Sdjl 
707*cb5caa98Sdjl 		be = s->be[n_src];
708*cb5caa98Sdjl 		if (be != NULL)
709*cb5caa98Sdjl 			funcp = NSS_LOOKUP_DBOP(be, search_fnum);
710*cb5caa98Sdjl 
711*cb5caa98Sdjl 		if ((params.dnsi >= 0 && be == 0) || (params.dnsi  < 0 &&
712*cb5caa98Sdjl 			(be == 0 || (smf_state != NSCD_SVC_STATE_UNINITED &&
713*cb5caa98Sdjl 			smf_state < SCF_STATE_ONLINE) || funcp == 0))) {
714*cb5caa98Sdjl 
715*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
716*cb5caa98Sdjl 					NSCD_LOG_LEVEL_DEBUG)
717*cb5caa98Sdjl 			(me, "unable to look up source %s: be = %p, "
718*cb5caa98Sdjl 			"smf state = %d, funcp = %p\n",
719*cb5caa98Sdjl 			NSCD_NSW_SRC_NAME(srci), be, smf_state, funcp);
720*cb5caa98Sdjl 
721*cb5caa98Sdjl 			goto next_src;
722*cb5caa98Sdjl 		}
723*cb5caa98Sdjl 
724*cb5caa98Sdjl 		do {
725*cb5caa98Sdjl 			/*
726*cb5caa98Sdjl 			 * we can only retry max_retry times,
727*cb5caa98Sdjl 			 * otherwise threads may get stuck in this
728*cb5caa98Sdjl 			 * do-while loop forever
729*cb5caa98Sdjl 			 */
730*cb5caa98Sdjl 			if (n_loop > max_retry) {
731*cb5caa98Sdjl 				if (swret != NULL)
732*cb5caa98Sdjl 					res = NSS_TRYLOCAL;
733*cb5caa98Sdjl 				goto free_nsw_state;
734*cb5caa98Sdjl 			}
735*cb5caa98Sdjl 
736*cb5caa98Sdjl 			/*
737*cb5caa98Sdjl 			 * set up to prevent loopback
738*cb5caa98Sdjl 			 */
739*cb5caa98Sdjl 			if (check_loopback && k == NULL) {
740*cb5caa98Sdjl 				key.srci = srci;
741*cb5caa98Sdjl 				key.dbi = dbi;
742*cb5caa98Sdjl 				key.fnum = search_fnum;
743*cb5caa98Sdjl 				key.lb_flagp = &check_loopback;
744*cb5caa98Sdjl 				(void) set_loopback_key(&key);
745*cb5caa98Sdjl 				k = &key;
746*cb5caa98Sdjl 			}
747*cb5caa98Sdjl 
748*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
749*cb5caa98Sdjl 					NSCD_LOG_LEVEL_DEBUG)
750*cb5caa98Sdjl 			(me, "looking up source = %s, loop# = %d \n",
751*cb5caa98Sdjl 			NSCD_NSW_SRC_NAME(srci), n_loop);
752*cb5caa98Sdjl 
753*cb5caa98Sdjl 			/*
754*cb5caa98Sdjl 			 * search the backend, if hosts lookups,
755*cb5caa98Sdjl 			 * try to get the hosts data with ttl first
756*cb5caa98Sdjl 			 */
757*cb5caa98Sdjl 			if (params.dnsi >= 0) {
758*cb5caa98Sdjl 				res = search_dns_withttl(swret,
759*cb5caa98Sdjl 					NSCD_NSW_SRC_NAME(srci),
760*cb5caa98Sdjl 					params.dnsi);
761*cb5caa98Sdjl 				/*
762*cb5caa98Sdjl 				 * if not able to get ttl, fall back
763*cb5caa98Sdjl 				 * to the regular backend call
764*cb5caa98Sdjl 				 */
765*cb5caa98Sdjl 				if (res == NSS_ERROR)
766*cb5caa98Sdjl 					res = (*funcp)(be, search_args);
767*cb5caa98Sdjl 				else {
768*cb5caa98Sdjl 					/*
769*cb5caa98Sdjl 					 * status/result are in the
770*cb5caa98Sdjl 					 * packed buffer, not
771*cb5caa98Sdjl 					 * search_args
772*cb5caa98Sdjl 					 */
773*cb5caa98Sdjl 					swret->noarg = 1;
774*cb5caa98Sdjl 				}
775*cb5caa98Sdjl 			} else
776*cb5caa98Sdjl 				res = (*funcp)(be, search_args);
777*cb5caa98Sdjl 			if (swret != NULL)
778*cb5caa98Sdjl 				swret->errnum = errno;
779*cb5caa98Sdjl 
780*cb5caa98Sdjl 			/*
781*cb5caa98Sdjl 			 * backend is not up, check and update the
782*cb5caa98Sdjl 			 * smf state table
783*cb5caa98Sdjl 			 */
784*cb5caa98Sdjl 			if (res == NSS_UNAVAIL)
785*cb5caa98Sdjl 				(void) _nscd_get_smf_state(srci, dbi, 1);
786*cb5caa98Sdjl 
787*cb5caa98Sdjl 			/*
788*cb5caa98Sdjl 			 * may need to fall back to use the main nscd
789*cb5caa98Sdjl 			 * if per-user lookup
790*cb5caa98Sdjl 			 */
791*cb5caa98Sdjl 			if (_whoami == NSCD_CHILD && swret != NULL)
792*cb5caa98Sdjl 				swret->fallback = set_fallback_flag(
793*cb5caa98Sdjl 				NSCD_NSW_SRC_NAME(srci), res);
794*cb5caa98Sdjl 
795*cb5caa98Sdjl 			_NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE,
796*cb5caa98Sdjl 					NSCD_LOG_LEVEL_DEBUG) {
797*cb5caa98Sdjl 
798*cb5caa98Sdjl 				/*
799*cb5caa98Sdjl 				 * set up to trace the result/status
800*cb5caa98Sdjl 				 * of the dns/ttl lookup
801*cb5caa98Sdjl 				 */
802*cb5caa98Sdjl 				if (swret != NULL && swret->noarg == 1) {
803*cb5caa98Sdjl 					nss_pheader_t *phdr;
804*cb5caa98Sdjl 					struct nss_XbyY_args *arg;
805*cb5caa98Sdjl 					arg = (struct nss_XbyY_args *)
806*cb5caa98Sdjl 						search_args;
807*cb5caa98Sdjl 					phdr = (nss_pheader_t *)swret->pbuf;
808*cb5caa98Sdjl 					arg->buf.buffer = (char *)phdr +
809*cb5caa98Sdjl 						phdr->data_off;
810*cb5caa98Sdjl 					arg->returnlen = phdr->data_len;
811*cb5caa98Sdjl 					if (phdr->p_errno == ERANGE)
812*cb5caa98Sdjl 						arg->erange = 1;
813*cb5caa98Sdjl 					arg->h_errno = phdr->p_herrno;
814*cb5caa98Sdjl 				}
815*cb5caa98Sdjl 
816*cb5caa98Sdjl 				trace_result(dbi, srci, search_fnum, res,
817*cb5caa98Sdjl 				(nss_XbyY_args_t *)search_args);
818*cb5caa98Sdjl 			}
819*cb5caa98Sdjl 
820*cb5caa98Sdjl 			n_loop++;
821*cb5caa98Sdjl 		} while (retry_test(res, n_loop, lkp));
822*cb5caa98Sdjl 
823*cb5caa98Sdjl 		next_src:
824*cb5caa98Sdjl 
825*cb5caa98Sdjl 		status_vec |= (1 << res);
826*cb5caa98Sdjl 
827*cb5caa98Sdjl 		if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) {
828*cb5caa98Sdjl 			break;
829*cb5caa98Sdjl 		}
830*cb5caa98Sdjl 	}
831*cb5caa98Sdjl 
832*cb5caa98Sdjl 	free_nsw_state:
833*cb5caa98Sdjl 
834*cb5caa98Sdjl 	if (state_thr == 1)
835*cb5caa98Sdjl 		_nscd_put_nsw_state_thread(s);
836*cb5caa98Sdjl 	else
837*cb5caa98Sdjl 		_nscd_put_nsw_state(s);
838*cb5caa98Sdjl 	if (check_loopback && k != NULL)
839*cb5caa98Sdjl 		clear_loopback_key(k);
840*cb5caa98Sdjl 
841*cb5caa98Sdjl 	if (res != NSS_SUCCESS)
842*cb5caa98Sdjl 		goto error_exit;
843*cb5caa98Sdjl 
844*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_succeeded_g++;
845*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_succeeded++;
846*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g--;
847*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress--;
848*cb5caa98Sdjl 
849*cb5caa98Sdjl 	return (NSS_SUCCESS);
850*cb5caa98Sdjl 
851*cb5caa98Sdjl 	error_exit:
852*cb5caa98Sdjl 
853*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_failed_g++;
854*cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g--;
855*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_failed++;
856*cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress--;
857*cb5caa98Sdjl 
858*cb5caa98Sdjl 	return (res);
859*cb5caa98Sdjl }
860*cb5caa98Sdjl 
861*cb5caa98Sdjl 
862*cb5caa98Sdjl /* ===> get/set/endent */
863*cb5caa98Sdjl 
864*cb5caa98Sdjl static void		nss_setent_u(nss_db_root_t *,
865*cb5caa98Sdjl 				    nss_db_initf_t,
866*cb5caa98Sdjl 				    nss_getent_t *);
867*cb5caa98Sdjl static nss_status_t	nss_getent_u(nss_db_root_t *,
868*cb5caa98Sdjl 				    nss_db_initf_t,
869*cb5caa98Sdjl 				    nss_getent_t *,
870*cb5caa98Sdjl 				    void *);
871*cb5caa98Sdjl static void		nss_endent_u(nss_db_root_t *,
872*cb5caa98Sdjl 				    nss_db_initf_t,
873*cb5caa98Sdjl 				    nss_getent_t *);
874*cb5caa98Sdjl 
875*cb5caa98Sdjl void
876*cb5caa98Sdjl nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf,
877*cb5caa98Sdjl 	nss_getent_t *contextpp)
878*cb5caa98Sdjl {
879*cb5caa98Sdjl 	if (contextpp == 0)
880*cb5caa98Sdjl 		return;
881*cb5caa98Sdjl 	nss_setent_u(rootp, initf, contextpp);
882*cb5caa98Sdjl }
883*cb5caa98Sdjl 
884*cb5caa98Sdjl nss_status_t
885*cb5caa98Sdjl nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp,
886*cb5caa98Sdjl 	void *args)
887*cb5caa98Sdjl {
888*cb5caa98Sdjl 	nss_status_t		status;
889*cb5caa98Sdjl 
890*cb5caa98Sdjl 	if (contextpp == 0) {
891*cb5caa98Sdjl 		return (NSS_UNAVAIL);
892*cb5caa98Sdjl 	}
893*cb5caa98Sdjl 	status = nss_getent_u(rootp, initf, contextpp, args);
894*cb5caa98Sdjl 	return (status);
895*cb5caa98Sdjl }
896*cb5caa98Sdjl 
897*cb5caa98Sdjl void
898*cb5caa98Sdjl nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf,
899*cb5caa98Sdjl 	nss_getent_t *contextpp)
900*cb5caa98Sdjl {
901*cb5caa98Sdjl 	if (contextpp == 0)
902*cb5caa98Sdjl 		return;
903*cb5caa98Sdjl 	nss_endent_u(rootp, initf, contextpp);
904*cb5caa98Sdjl }
905*cb5caa98Sdjl 
906*cb5caa98Sdjl /*ARGSUSED*/
907*cb5caa98Sdjl static void
908*cb5caa98Sdjl end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp)
909*cb5caa98Sdjl {
910*cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
911*cb5caa98Sdjl 	nscd_nsw_state_t	*s;
912*cb5caa98Sdjl 	nss_backend_t		*be;
913*cb5caa98Sdjl 	int			n_src;
914*cb5caa98Sdjl 
915*cb5caa98Sdjl 	ctx = (nscd_getent_context_t *)contextp;
916*cb5caa98Sdjl 	s = ctx->nsw_state;
917*cb5caa98Sdjl 	n_src = ctx->n_src;
918*cb5caa98Sdjl 	be = ctx->be;
919*cb5caa98Sdjl 
920*cb5caa98Sdjl 	if (s != 0) {
921*cb5caa98Sdjl 		if (n_src < s->max_src && be != 0) {
922*cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
923*cb5caa98Sdjl 			ctx->be = 0;  /* Should be unnecessary, but hey */
924*cb5caa98Sdjl 		}
925*cb5caa98Sdjl 	}
926*cb5caa98Sdjl 	ctx->n_src = 0;
927*cb5caa98Sdjl }
928*cb5caa98Sdjl 
929*cb5caa98Sdjl static void
930*cb5caa98Sdjl nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
931*cb5caa98Sdjl 	nss_getent_t *contextpp)
932*cb5caa98Sdjl {
933*cb5caa98Sdjl 	char			*me = "nss_setent_u";
934*cb5caa98Sdjl 	nscd_nsw_state_t	*s;
935*cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
936*cb5caa98Sdjl 	nscd_nsw_params_t	params;
937*cb5caa98Sdjl 	nss_db_root_t		root;
938*cb5caa98Sdjl 	nss_backend_t		*be;
939*cb5caa98Sdjl 	int			n_src, i;
940*cb5caa98Sdjl 	nscd_sw_return_t	*swret = NULL;
941*cb5caa98Sdjl 
942*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
943*cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p \n",
944*cb5caa98Sdjl 		rootp, initf, contextpp);
945*cb5caa98Sdjl 
946*cb5caa98Sdjl 	/* get the nsw db index via the initf function */
947*cb5caa98Sdjl 	(void) getparams(-1, initf, &params);
948*cb5caa98Sdjl 
949*cb5caa98Sdjl 	/* get address of the switch engine return data area */
950*cb5caa98Sdjl 	if (initf == nscd_initf)
951*cb5caa98Sdjl 		swret = (nscd_sw_return_t *)params.p.private;
952*cb5caa98Sdjl 
953*cb5caa98Sdjl 	/* if no privilege to look up, return */
954*cb5caa98Sdjl 	if (params.privdb == 1 && swret != NULL &&
955*cb5caa98Sdjl 		((nss_pheader_t *)(swret->pbuf))->p_euid != 0) {
956*cb5caa98Sdjl 
957*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
958*cb5caa98Sdjl 		(me, "no privilege \n");
959*cb5caa98Sdjl 		return;
960*cb5caa98Sdjl 	}
961*cb5caa98Sdjl 
962*cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
963*cb5caa98Sdjl 		if ((_nscd_get_getent_ctx(contextpp, &params)) !=
964*cb5caa98Sdjl 			NSCD_SUCCESS) {
965*cb5caa98Sdjl 			return;
966*cb5caa98Sdjl 		}
967*cb5caa98Sdjl 		contextp = (nscd_getent_context_t *)contextpp->ctx;
968*cb5caa98Sdjl 	}
969*cb5caa98Sdjl 	s = contextp->nsw_state;
970*cb5caa98Sdjl 
971*cb5caa98Sdjl 	if (s == 0) {
972*cb5caa98Sdjl 		if (_nscd_get_nsw_state(&root, &params) !=
973*cb5caa98Sdjl 				NSCD_SUCCESS) {
974*cb5caa98Sdjl 			return;
975*cb5caa98Sdjl 		}
976*cb5caa98Sdjl 		s = (nscd_nsw_state_t *)root.s;
977*cb5caa98Sdjl 		contextp->nsw_state = s;
978*cb5caa98Sdjl 
979*cb5caa98Sdjl 	} else {
980*cb5caa98Sdjl 		s	= contextp->nsw_state;
981*cb5caa98Sdjl 		n_src	= contextp->n_src;
982*cb5caa98Sdjl 		be	= contextp->be;
983*cb5caa98Sdjl 		if (n_src == 0 && be != 0) {
984*cb5caa98Sdjl 			/*
985*cb5caa98Sdjl 			 * Optimization:  don't do endent, don't change
986*cb5caa98Sdjl 			 *   backends, just do the setent.  Look Ma, no locks
987*cb5caa98Sdjl 			 *   (nor any context that needs updating).
988*cb5caa98Sdjl 			 */
989*cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
990*cb5caa98Sdjl 			return;
991*cb5caa98Sdjl 		}
992*cb5caa98Sdjl 		if (n_src < s->max_src && be != 0) {
993*cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
994*cb5caa98Sdjl 			contextp->be = 0;	/* Play it safe */
995*cb5caa98Sdjl 		}
996*cb5caa98Sdjl 	}
997*cb5caa98Sdjl 	for (n_src = 0, be = 0; n_src < s->max_src &&
998*cb5caa98Sdjl 		(be = s->be[n_src]) == 0; n_src++) {
999*cb5caa98Sdjl 		;
1000*cb5caa98Sdjl 	}
1001*cb5caa98Sdjl 
1002*cb5caa98Sdjl 	contextp->n_src	= n_src;
1003*cb5caa98Sdjl 	contextp->be	= be;
1004*cb5caa98Sdjl 
1005*cb5caa98Sdjl 	if (be == 0) {
1006*cb5caa98Sdjl 		/* Things are broken enough that we can't do setent/getent */
1007*cb5caa98Sdjl 		nss_endent_u(rootp, initf, contextpp);
1008*cb5caa98Sdjl 		return;
1009*cb5caa98Sdjl 	}
1010*cb5caa98Sdjl 
1011*cb5caa98Sdjl 	/*
1012*cb5caa98Sdjl 	 * make sure all the backends are supported
1013*cb5caa98Sdjl 	 */
1014*cb5caa98Sdjl 	for (i = 0; i < s->max_src; i++) {
1015*cb5caa98Sdjl 		int	st, srci;
1016*cb5caa98Sdjl 
1017*cb5caa98Sdjl 		srci = (*s->nsw_cfg_p)->src_idx[i];
1018*cb5caa98Sdjl 		st = _nscd_get_smf_state(srci, params.dbi, 1);
1019*cb5caa98Sdjl 		if (st == NSCD_SVC_STATE_UNKNOWN_SRC ||
1020*cb5caa98Sdjl 				st == NSCD_SVC_STATE_UNINITED) {
1021*cb5caa98Sdjl 			nss_endent_u(rootp, initf, contextpp);
1022*cb5caa98Sdjl 
1023*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1024*cb5caa98Sdjl 				NSCD_LOG_LEVEL_DEBUG)
1025*cb5caa98Sdjl 			(me, "backend (%s) not available (state = %d)\n",
1026*cb5caa98Sdjl 			NSCD_NSW_SRC_NAME(srci), st);
1027*cb5caa98Sdjl 
1028*cb5caa98Sdjl 			return;
1029*cb5caa98Sdjl 		}
1030*cb5caa98Sdjl 	}
1031*cb5caa98Sdjl 
1032*cb5caa98Sdjl 	(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
1033*cb5caa98Sdjl }
1034*cb5caa98Sdjl 
1035*cb5caa98Sdjl nss_status_t
1036*cb5caa98Sdjl nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
1037*cb5caa98Sdjl 	nss_getent_t *contextpp, void *args)
1038*cb5caa98Sdjl {
1039*cb5caa98Sdjl 	char			*me = "nss_getent_u";
1040*cb5caa98Sdjl 	nscd_nsw_state_t	*s;
1041*cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
1042*cb5caa98Sdjl 	int			n_src;
1043*cb5caa98Sdjl 	nss_backend_t		*be;
1044*cb5caa98Sdjl 
1045*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1046*cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p, args = %p\n",
1047*cb5caa98Sdjl 		rootp, initf, contextpp, args);
1048*cb5caa98Sdjl 
1049*cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1050*cb5caa98Sdjl 		nss_setent_u(rootp, initf, contextpp);
1051*cb5caa98Sdjl 		if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1052*cb5caa98Sdjl 			/* Give up */
1053*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1054*cb5caa98Sdjl 				NSCD_LOG_LEVEL_ERROR)
1055*cb5caa98Sdjl 			(me, "not able to obtain getent context ... give up\n");
1056*cb5caa98Sdjl 
1057*cb5caa98Sdjl 			return (NSS_UNAVAIL);
1058*cb5caa98Sdjl 		}
1059*cb5caa98Sdjl 	}
1060*cb5caa98Sdjl 
1061*cb5caa98Sdjl 	s	= contextp->nsw_state;
1062*cb5caa98Sdjl 	n_src	= contextp->n_src;
1063*cb5caa98Sdjl 	be	= contextp->be;
1064*cb5caa98Sdjl 
1065*cb5caa98Sdjl 	if (s == 0) {
1066*cb5caa98Sdjl 		/*
1067*cb5caa98Sdjl 		 * We've done an end_iter() and haven't done nss_setent()
1068*cb5caa98Sdjl 		 * or nss_endent() since;  we should stick in this state
1069*cb5caa98Sdjl 		 * until the caller invokes one of those two routines.
1070*cb5caa98Sdjl 		 */
1071*cb5caa98Sdjl 		return (NSS_SUCCESS);
1072*cb5caa98Sdjl 	}
1073*cb5caa98Sdjl 
1074*cb5caa98Sdjl 	while (n_src < s->max_src) {
1075*cb5caa98Sdjl 		nss_status_t		res;
1076*cb5caa98Sdjl 		struct __nsw_lookup_v1	*lkp = NULL;
1077*cb5caa98Sdjl 		int			n;
1078*cb5caa98Sdjl 
1079*cb5caa98Sdjl 		/* get the nsw config for the current source */
1080*cb5caa98Sdjl 		lkp = s->config->lookups;
1081*cb5caa98Sdjl 		for (n = 0; n < n_src; n++)
1082*cb5caa98Sdjl 			lkp = lkp->next;
1083*cb5caa98Sdjl 
1084*cb5caa98Sdjl 		if (be == 0) {
1085*cb5caa98Sdjl 			/* If it's null it's a bug, but let's play safe */
1086*cb5caa98Sdjl 			res = NSS_UNAVAIL;
1087*cb5caa98Sdjl 		} else {
1088*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1089*cb5caa98Sdjl 					NSCD_LOG_LEVEL_DEBUG)
1090*cb5caa98Sdjl 			(me, "database: %s, backend: %s, nsswitch config: %s\n",
1091*cb5caa98Sdjl 				NSCD_NSW_DB_NAME(s->dbi),
1092*cb5caa98Sdjl 				lkp->service_name,
1093*cb5caa98Sdjl 				(*s->nsw_cfg_p)->nsw_cfg_str);
1094*cb5caa98Sdjl 
1095*cb5caa98Sdjl 			res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args);
1096*cb5caa98Sdjl 		}
1097*cb5caa98Sdjl 
1098*cb5caa98Sdjl 		if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) {
1099*cb5caa98Sdjl 			if (res != __NSW_SUCCESS) {
1100*cb5caa98Sdjl 				end_iter_u(rootp,
1101*cb5caa98Sdjl 					(struct nss_getent_context *)contextp);
1102*cb5caa98Sdjl 			}
1103*cb5caa98Sdjl 			return (res);
1104*cb5caa98Sdjl 		}
1105*cb5caa98Sdjl 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
1106*cb5caa98Sdjl 		do {
1107*cb5caa98Sdjl 			n_src++;
1108*cb5caa98Sdjl 		} while (n_src < s->max_src &&
1109*cb5caa98Sdjl 				(be = s->be[n_src]) == 0);
1110*cb5caa98Sdjl 		if (be == 0) {
1111*cb5caa98Sdjl 			/*
1112*cb5caa98Sdjl 			 * This is the case where we failed to get the backend
1113*cb5caa98Sdjl 			 * for the last source. We exhausted all sources.
1114*cb5caa98Sdjl 			 */
1115*cb5caa98Sdjl 			nss_endent_u(rootp, initf, contextpp);
1116*cb5caa98Sdjl 			return (NSS_SUCCESS);
1117*cb5caa98Sdjl 		}
1118*cb5caa98Sdjl 		contextp->n_src	= n_src;
1119*cb5caa98Sdjl 		contextp->be	= be;
1120*cb5caa98Sdjl 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
1121*cb5caa98Sdjl 	}
1122*cb5caa98Sdjl 	/* Got to the end of the sources without finding another entry */
1123*cb5caa98Sdjl 	end_iter_u(rootp, (struct nss_getent_context *)contextp);
1124*cb5caa98Sdjl 	return (NSS_SUCCESS);
1125*cb5caa98Sdjl 	/* success is either a successful entry or end of the sources */
1126*cb5caa98Sdjl }
1127*cb5caa98Sdjl 
1128*cb5caa98Sdjl /*ARGSUSED*/
1129*cb5caa98Sdjl void
1130*cb5caa98Sdjl nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
1131*cb5caa98Sdjl 	nss_getent_t *contextpp)
1132*cb5caa98Sdjl {
1133*cb5caa98Sdjl 	char			*me = "nss_endent_u";
1134*cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
1135*cb5caa98Sdjl 
1136*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1137*cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p \n",
1138*cb5caa98Sdjl 		rootp, initf, contextpp);
1139*cb5caa98Sdjl 
1140*cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1141*cb5caa98Sdjl 		/* nss_endent() on an unused context is a no-op */
1142*cb5caa98Sdjl 		return;
1143*cb5caa98Sdjl 	}
1144*cb5caa98Sdjl 	end_iter_u(rootp, (struct nss_getent_context *)contextp);
1145*cb5caa98Sdjl 	_nscd_put_getent_ctx(contextp);
1146*cb5caa98Sdjl 	contextpp->ctx = NULL;
1147*cb5caa98Sdjl }
1148*cb5caa98Sdjl 
1149*cb5caa98Sdjl /*
1150*cb5caa98Sdjl  * _nss_db_state_destr() and nss_delete() do nothing in nscd
1151*cb5caa98Sdjl  * but is needed to make the caller (below nscd) happy
1152*cb5caa98Sdjl  */
1153*cb5caa98Sdjl /*ARGSUSED*/
1154*cb5caa98Sdjl void
1155*cb5caa98Sdjl _nss_db_state_destr(struct nss_db_state *s)
1156*cb5caa98Sdjl {
1157*cb5caa98Sdjl 	/* nsw state in nscd is always reused, so do nothing here */
1158*cb5caa98Sdjl }
1159*cb5caa98Sdjl 
1160*cb5caa98Sdjl /*ARGSUSED*/
1161*cb5caa98Sdjl void
1162*cb5caa98Sdjl nss_delete(nss_db_root_t *rootp)
1163*cb5caa98Sdjl {
1164*cb5caa98Sdjl 	/*
1165*cb5caa98Sdjl 	 * the only resource kept tracked by the nss_db_root_t
1166*cb5caa98Sdjl 	 * is the nsw state which is always reused and no need
1167*cb5caa98Sdjl 	 * to be freed. So just return.
1168*cb5caa98Sdjl 	 */
1169*cb5caa98Sdjl }
1170*cb5caa98Sdjl 
1171*cb5caa98Sdjl /*
1172*cb5caa98Sdjl  * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent()
1173*cb5caa98Sdjl  * buffers switch entry points
1174*cb5caa98Sdjl  */
1175*cb5caa98Sdjl 
1176*cb5caa98Sdjl /*
1177*cb5caa98Sdjl  * nss_psearch opens a packed structure header, assembles a local
1178*cb5caa98Sdjl  * nss_XbyY_args_t structure and calls the local copy of nss_search.
1179*cb5caa98Sdjl  * The return data is assembled in "files native format" in the
1180*cb5caa98Sdjl  * return buffer location.  Status if packed back up with the buffer
1181*cb5caa98Sdjl  * and the whole wad is returned to the cache or the client.
1182*cb5caa98Sdjl  */
1183*cb5caa98Sdjl 
1184*cb5caa98Sdjl void
1185*cb5caa98Sdjl nss_psearch(void *buffer, size_t length)
1186*cb5caa98Sdjl {
1187*cb5caa98Sdjl 	/* inputs */
1188*cb5caa98Sdjl 	nss_db_initf_t		initf;
1189*cb5caa98Sdjl 	int			dbop;
1190*cb5caa98Sdjl 	int			rc;
1191*cb5caa98Sdjl 	nss_XbyY_args_t		arg;
1192*cb5caa98Sdjl 	nss_status_t		status;
1193*cb5caa98Sdjl 	nscd_sw_return_t	swret = { 0 }, *swrp = &swret;
1194*cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1195*cb5caa98Sdjl 	char			*me = "nss_psearch";
1196*cb5caa98Sdjl 
1197*cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1198*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1199*cb5caa98Sdjl 	}
1200*cb5caa98Sdjl 
1201*cb5caa98Sdjl 	status = nss_packed_arg_init(buffer, length,
1202*cb5caa98Sdjl 			NULL, &initf, &dbop, &arg);
1203*cb5caa98Sdjl 	if (status != NSS_SUCCESS) {
1204*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, status, -1);
1205*cb5caa98Sdjl 	}
1206*cb5caa98Sdjl 
1207*cb5caa98Sdjl 	/*
1208*cb5caa98Sdjl 	 * pass the address of the return data area
1209*cb5caa98Sdjl 	 * for the switch engine to return its own data
1210*cb5caa98Sdjl 	 */
1211*cb5caa98Sdjl 	(void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp));
1212*cb5caa98Sdjl 	swret.pbuf = buffer;
1213*cb5caa98Sdjl 	swret.pbufsiz = length;
1214*cb5caa98Sdjl 
1215*cb5caa98Sdjl 	/*
1216*cb5caa98Sdjl 	 * use the generic nscd_initf for all database lookups
1217*cb5caa98Sdjl 	 * (the TSD key is the pointer to the packed header)
1218*cb5caa98Sdjl 	 */
1219*cb5caa98Sdjl 	rc = set_initf_key(pbuf);
1220*cb5caa98Sdjl 	if (rc != 0) {
1221*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL);
1222*cb5caa98Sdjl 	}
1223*cb5caa98Sdjl 	initf = nscd_initf;
1224*cb5caa98Sdjl 
1225*cb5caa98Sdjl 	/* Perform local search and pack results into return buffer */
1226*cb5caa98Sdjl 	/* nscd's search ignores db_root */
1227*cb5caa98Sdjl 	status = nss_search(NULL, initf, dbop, &arg);
1228*cb5caa98Sdjl 
1229*cb5caa98Sdjl 	/*
1230*cb5caa98Sdjl 	 * If status is NSS_NOTFOUND and ldap also returned
1231*cb5caa98Sdjl 	 * NSS_NOTFOUND, it is possible that the user does
1232*cb5caa98Sdjl 	 * not have a credential, so check and see if
1233*cb5caa98Sdjl 	 * needs to return NSS_ALTRETRY to let the main
1234*cb5caa98Sdjl 	 * nscd get a chance to process the lookup
1235*cb5caa98Sdjl 	 */
1236*cb5caa98Sdjl 	if (swret.fallback == 1 && status == NSS_NOTFOUND) {
1237*cb5caa98Sdjl 		OM_uint32 stat;
1238*cb5caa98Sdjl 
1239*cb5caa98Sdjl 		if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL,
1240*cb5caa98Sdjl 			NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) {
1241*cb5caa98Sdjl 
1242*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1243*cb5caa98Sdjl 				NSCD_LOG_LEVEL_DEBUG)
1244*cb5caa98Sdjl 			(me, "NSS_ALTRETRY: fallback to main nscd needed\n");
1245*cb5caa98Sdjl 
1246*cb5caa98Sdjl 			status = NSS_ALTRETRY;
1247*cb5caa98Sdjl 		}
1248*cb5caa98Sdjl 	}
1249*cb5caa98Sdjl 
1250*cb5caa98Sdjl 	NSCD_SET_STATUS(pbuf, status, -1);
1251*cb5caa98Sdjl 	errno = swret.errnum;
1252*cb5caa98Sdjl 
1253*cb5caa98Sdjl 	/*
1254*cb5caa98Sdjl 	 * move result/status from args to packed buffer only if
1255*cb5caa98Sdjl 	 * arg was being used
1256*cb5caa98Sdjl 	 */
1257*cb5caa98Sdjl 	if (!swret.noarg)
1258*cb5caa98Sdjl 		nss_packed_set_status(buffer, length, status,  &arg);
1259*cb5caa98Sdjl 
1260*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1261*cb5caa98Sdjl 	(me, "switch engine result: source is %s, status %d, "
1262*cb5caa98Sdjl 	"herrno is %d, errno is %s\n",
1263*cb5caa98Sdjl 	(swret.srci != -1) ? NSCD_NSW_SRC_NAME(swret.srci) : "<NOTSET>",
1264*cb5caa98Sdjl 	pbuf->p_status, pbuf->p_herrno, strerror(pbuf->p_errno));
1265*cb5caa98Sdjl 
1266*cb5caa98Sdjl 	/* clear the TSD key used by the generic initf */
1267*cb5caa98Sdjl 	clear_initf_key();
1268*cb5caa98Sdjl 	pbuf->nscdpriv = 0;
1269*cb5caa98Sdjl }
1270*cb5caa98Sdjl 
1271*cb5caa98Sdjl static void
1272*cb5caa98Sdjl nscd_map_contextp(void *buffer, nss_getent_t *contextp,
1273*cb5caa98Sdjl 	nssuint_t **cookie_p, nssuint_t **seqnum_p, int setent)
1274*cb5caa98Sdjl {
1275*cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1276*cb5caa98Sdjl 	nssuint_t		off;
1277*cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1278*cb5caa98Sdjl 	char			*me = "nscd_map_contextp";
1279*cb5caa98Sdjl 
1280*cb5caa98Sdjl 	struct cookie_seqnum {
1281*cb5caa98Sdjl 		nssuint_t	cookie;
1282*cb5caa98Sdjl 		nssuint_t	seqnum;
1283*cb5caa98Sdjl 	} *csp;
1284*cb5caa98Sdjl 
1285*cb5caa98Sdjl 	if (buffer == NULL) {
1286*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1287*cb5caa98Sdjl 	}
1288*cb5caa98Sdjl 
1289*cb5caa98Sdjl 	off = pbuf->key_off;
1290*cb5caa98Sdjl 	csp = (struct cookie_seqnum *)((void *)((char *)buffer + off));
1291*cb5caa98Sdjl 	if (seqnum_p != NULL)
1292*cb5caa98Sdjl 		*seqnum_p = &csp->seqnum;
1293*cb5caa98Sdjl 
1294*cb5caa98Sdjl 	/*
1295*cb5caa98Sdjl 	 * if called by nss_psetent, and the passed in cookie is
1296*cb5caa98Sdjl 	 * NSCD_NEW_COOKIE, then there is no cookie yet, return
1297*cb5caa98Sdjl 	 * a pointer pointing to where the cookie will be stored.
1298*cb5caa98Sdjl 	 * Also because there is no cookie to validate, just
1299*cb5caa98Sdjl 	 * return success.
1300*cb5caa98Sdjl 	 *
1301*cb5caa98Sdjl 	 * On the other hand, if a cookie is passed in, we need
1302*cb5caa98Sdjl 	 * to validate the cookie before returning.
1303*cb5caa98Sdjl 	 */
1304*cb5caa98Sdjl 	if (cookie_p != NULL)
1305*cb5caa98Sdjl 		*cookie_p = &csp->cookie;
1306*cb5caa98Sdjl 	if (setent == 1 && csp->cookie == NSCD_NEW_COOKIE) {
1307*cb5caa98Sdjl 		NSCD_RETURN_STATUS_SUCCESS(pbuf);
1308*cb5caa98Sdjl 	}
1309*cb5caa98Sdjl 
1310*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1311*cb5caa98Sdjl 	(me, "cookie = %lld,  sequence number = %lld\n",
1312*cb5caa98Sdjl 		csp->cookie, csp->seqnum);
1313*cb5caa98Sdjl 
1314*cb5caa98Sdjl 	ctx = _nscd_is_getent_ctx(csp->cookie);
1315*cb5caa98Sdjl 
1316*cb5caa98Sdjl 	if (ctx == NULL) {
1317*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1318*cb5caa98Sdjl 		(me, "invalid cookie (%lld)\n", csp->cookie);
1319*cb5caa98Sdjl 
1320*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1321*cb5caa98Sdjl 	}
1322*cb5caa98Sdjl 
1323*cb5caa98Sdjl 	if (setent == 1) {
1324*cb5caa98Sdjl 		/* if called by nss_psetent, reset the seq number */
1325*cb5caa98Sdjl 		ctx->seq_num = 1;
1326*cb5caa98Sdjl 	} else if (ctx->seq_num != (nscd_seq_num_t)csp->seqnum) {
1327*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1328*cb5caa98Sdjl 		(me, "invalid sequence number (%lld)\n", csp->seqnum);
1329*cb5caa98Sdjl 
1330*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1331*cb5caa98Sdjl 	}
1332*cb5caa98Sdjl 
1333*cb5caa98Sdjl 	contextp->ctx = (struct nss_getent_context *)ctx;
1334*cb5caa98Sdjl 
1335*cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(pbuf);
1336*cb5caa98Sdjl }
1337*cb5caa98Sdjl 
1338*cb5caa98Sdjl void
1339*cb5caa98Sdjl nss_psetent(void *buffer, size_t length, pid_t pid)
1340*cb5caa98Sdjl {
1341*cb5caa98Sdjl 	/* inputs */
1342*cb5caa98Sdjl 	nss_db_initf_t		initf;
1343*cb5caa98Sdjl 	nss_getent_t		context = { 0 };
1344*cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1345*cb5caa98Sdjl 	nss_status_t		status;
1346*cb5caa98Sdjl 	nssuint_t		*cookiep;
1347*cb5caa98Sdjl 	nssuint_t		*seqnump;
1348*cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1349*cb5caa98Sdjl 	int			rc;
1350*cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1351*cb5caa98Sdjl 	nscd_sw_return_t	swret = { 0 }, *swrp = &swret;
1352*cb5caa98Sdjl 	char			*me = "nss_psetent";
1353*cb5caa98Sdjl 
1354*cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1355*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1356*cb5caa98Sdjl 	}
1357*cb5caa98Sdjl 
1358*cb5caa98Sdjl 	/*
1359*cb5caa98Sdjl 	 * If this is a per-user nscd, and the user does not have
1360*cb5caa98Sdjl 	 * the necessary credential, return NSS_TRYLOCAL, so the
1361*cb5caa98Sdjl 	 * setent/getent can be done locally in the process of the
1362*cb5caa98Sdjl 	 * setent call
1363*cb5caa98Sdjl 	 */
1364*cb5caa98Sdjl 	if (_whoami == NSCD_CHILD) {
1365*cb5caa98Sdjl 		OM_uint32 stat;
1366*cb5caa98Sdjl 
1367*cb5caa98Sdjl 		if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL,
1368*cb5caa98Sdjl 			NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) {
1369*cb5caa98Sdjl 
1370*cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1371*cb5caa98Sdjl 				NSCD_LOG_LEVEL_DEBUG)
1372*cb5caa98Sdjl 			(me, "NSS_TRYLOCAL: fallback to caller process\n");
1373*cb5caa98Sdjl 			NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0);
1374*cb5caa98Sdjl 		}
1375*cb5caa98Sdjl 	}
1376*cb5caa98Sdjl 
1377*cb5caa98Sdjl 	status = nss_packed_context_init(buffer, length,
1378*cb5caa98Sdjl 			NULL, &initf, &contextp, (nss_XbyY_args_t *)NULL);
1379*cb5caa98Sdjl 	if (status != NSS_SUCCESS) {
1380*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, status, -1);
1381*cb5caa98Sdjl 	}
1382*cb5caa98Sdjl 
1383*cb5caa98Sdjl 	/*
1384*cb5caa98Sdjl 	 * use the generic nscd_initf for all the setent requests
1385*cb5caa98Sdjl 	 * (the TSD key is the pointer to the packed header)
1386*cb5caa98Sdjl 	 */
1387*cb5caa98Sdjl 	rc = set_initf_key(pbuf);
1388*cb5caa98Sdjl 	if (rc != 0) {
1389*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL);
1390*cb5caa98Sdjl 	}
1391*cb5caa98Sdjl 	initf = nscd_initf;
1392*cb5caa98Sdjl 
1393*cb5caa98Sdjl 	/* get address of cookie and seqnum for later updates */
1394*cb5caa98Sdjl 	nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 1);
1395*cb5caa98Sdjl 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1396*cb5caa98Sdjl 		return;
1397*cb5caa98Sdjl 	/*
1398*cb5caa98Sdjl 	 * pass the packed header buffer pointer to nss_setent
1399*cb5caa98Sdjl 	 */
1400*cb5caa98Sdjl 	(void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp));
1401*cb5caa98Sdjl 	swret.pbuf = buffer;
1402*cb5caa98Sdjl 
1403*cb5caa98Sdjl 	/* Perform local setent and set context */
1404*cb5caa98Sdjl 	nss_setent(NULL, initf, contextp);
1405*cb5caa98Sdjl 
1406*cb5caa98Sdjl 	/* insert cookie info into buffer and return */
1407*cb5caa98Sdjl 	ctx = (nscd_getent_context_t *)contextp->ctx;
1408*cb5caa98Sdjl 	if (ctx != NULL) {
1409*cb5caa98Sdjl 		*cookiep = ctx->cookie;
1410*cb5caa98Sdjl 		*seqnump = (nssuint_t)ctx->seq_num;
1411*cb5caa98Sdjl 		ctx->pid = pid;
1412*cb5caa98Sdjl 	} else {
1413*cb5caa98Sdjl 		/*
1414*cb5caa98Sdjl 		 * not able to allocate a getent context, the
1415*cb5caa98Sdjl 		 * client should try the enumeration locally
1416*cb5caa98Sdjl 		 */
1417*cb5caa98Sdjl 		*cookiep = NSCD_LOCAL_COOKIE;
1418*cb5caa98Sdjl 		*seqnump = 0;
1419*cb5caa98Sdjl 	}
1420*cb5caa98Sdjl 
1421*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1422*cb5caa98Sdjl 	(me, "cookie = %lld,  sequence number = %lld\n",
1423*cb5caa98Sdjl 		*cookiep, *seqnump);
1424*cb5caa98Sdjl 
1425*cb5caa98Sdjl 	if (ctx != NULL) {
1426*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1427*cb5caa98Sdjl 		(me, "cookie = %lld,  sequence number = %lld\n",
1428*cb5caa98Sdjl 		ctx->cookie, ctx->seq_num);
1429*cb5caa98Sdjl 	}
1430*cb5caa98Sdjl 
1431*cb5caa98Sdjl 	/* clear the TSD key used by the generic initf */
1432*cb5caa98Sdjl 	clear_initf_key();
1433*cb5caa98Sdjl 
1434*cb5caa98Sdjl 	if (*cookiep == NSCD_LOCAL_COOKIE) {
1435*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0);
1436*cb5caa98Sdjl 	} else {
1437*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0);
1438*cb5caa98Sdjl 	}
1439*cb5caa98Sdjl }
1440*cb5caa98Sdjl 
1441*cb5caa98Sdjl void
1442*cb5caa98Sdjl nss_pgetent(void *buffer, size_t length)
1443*cb5caa98Sdjl {
1444*cb5caa98Sdjl 	/* inputs */
1445*cb5caa98Sdjl 	nss_db_initf_t		initf;
1446*cb5caa98Sdjl 	nss_getent_t		context;
1447*cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1448*cb5caa98Sdjl 	nss_XbyY_args_t		arg;
1449*cb5caa98Sdjl 	nss_status_t		status;
1450*cb5caa98Sdjl 	nssuint_t		*cookiep;
1451*cb5caa98Sdjl 	nssuint_t		*seqnump;
1452*cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1453*cb5caa98Sdjl 	int			rc;
1454*cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1455*cb5caa98Sdjl 	char			*me = "nss_pgetent";
1456*cb5caa98Sdjl 
1457*cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1458*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1459*cb5caa98Sdjl 	}
1460*cb5caa98Sdjl 
1461*cb5caa98Sdjl 	status = nss_packed_context_init(buffer, length,
1462*cb5caa98Sdjl 			NULL, &initf, &contextp, &arg);
1463*cb5caa98Sdjl 	if (status != NSS_SUCCESS) {
1464*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, status, -1);
1465*cb5caa98Sdjl 	}
1466*cb5caa98Sdjl 
1467*cb5caa98Sdjl 	/*
1468*cb5caa98Sdjl 	 * use the generic nscd_initf for all the getent requests
1469*cb5caa98Sdjl 	 * (the TSD key is the pointer to the packed header)
1470*cb5caa98Sdjl 	 */
1471*cb5caa98Sdjl 	rc = set_initf_key(pbuf);
1472*cb5caa98Sdjl 	if (rc != 0) {
1473*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL);
1474*cb5caa98Sdjl 	}
1475*cb5caa98Sdjl 	initf = nscd_initf;
1476*cb5caa98Sdjl 
1477*cb5caa98Sdjl 
1478*cb5caa98Sdjl 	/* verify the cookie passed in */
1479*cb5caa98Sdjl 	nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0);
1480*cb5caa98Sdjl 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1481*cb5caa98Sdjl 		return;
1482*cb5caa98Sdjl 
1483*cb5caa98Sdjl 	/* Perform local search and pack results into return buffer */
1484*cb5caa98Sdjl 	status = nss_getent(NULL, initf, contextp, &arg);
1485*cb5caa98Sdjl 	NSCD_SET_STATUS(pbuf, status, -1);
1486*cb5caa98Sdjl 	nss_packed_set_status(buffer, length, status,  &arg);
1487*cb5caa98Sdjl 
1488*cb5caa98Sdjl 	/* increment sequence number in the buffer and nscd context */
1489*cb5caa98Sdjl 	if (status == NSS_SUCCESS) {
1490*cb5caa98Sdjl 		ctx = (nscd_getent_context_t *)contextp->ctx;
1491*cb5caa98Sdjl 		ctx->seq_num++;
1492*cb5caa98Sdjl 		*seqnump = ctx->seq_num;
1493*cb5caa98Sdjl 		*cookiep = ctx->cookie;
1494*cb5caa98Sdjl 
1495*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1496*cb5caa98Sdjl 		(me, "getent OK, new sequence number = %lld, len = %lld,"
1497*cb5caa98Sdjl 		" data = [ %s ]\n", *seqnump,
1498*cb5caa98Sdjl 		pbuf->data_len, (char *)buffer + pbuf->data_off);
1499*cb5caa98Sdjl 	} else {
1500*cb5caa98Sdjl 		ctx = (nscd_getent_context_t *)contextp->ctx;
1501*cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1502*cb5caa98Sdjl 		(me, "getent failed, status = %d, sequence number = %lld\n",
1503*cb5caa98Sdjl 			status, *seqnump);
1504*cb5caa98Sdjl 	}
1505*cb5caa98Sdjl 
1506*cb5caa98Sdjl 	/* clear the TSD key used by the generic initf */
1507*cb5caa98Sdjl 	clear_initf_key();
1508*cb5caa98Sdjl }
1509*cb5caa98Sdjl 
1510*cb5caa98Sdjl void
1511*cb5caa98Sdjl nss_pendent(void *buffer, size_t length)
1512*cb5caa98Sdjl {
1513*cb5caa98Sdjl 	nss_getent_t		context;
1514*cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1515*cb5caa98Sdjl 	nssuint_t		*seqnump;
1516*cb5caa98Sdjl 	nssuint_t		*cookiep;
1517*cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1518*cb5caa98Sdjl 	char			*me = "nss_pendent";
1519*cb5caa98Sdjl 
1520*cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1521*cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1522*cb5caa98Sdjl 	}
1523*cb5caa98Sdjl 
1524*cb5caa98Sdjl 	/* map the contextp from the cookie information */
1525*cb5caa98Sdjl 	nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0);
1526*cb5caa98Sdjl 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1527*cb5caa98Sdjl 		return;
1528*cb5caa98Sdjl 
1529*cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1530*cb5caa98Sdjl 	(me, "endent, cookie = %lld, sequence number = %lld\n",
1531*cb5caa98Sdjl 		*cookiep, *seqnump);
1532*cb5caa98Sdjl 
1533*cb5caa98Sdjl 	/* Perform local endent and reset context */
1534*cb5caa98Sdjl 	nss_endent(NULL, NULL, contextp);
1535*cb5caa98Sdjl 	NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0);
1536*cb5caa98Sdjl }
1537*cb5caa98Sdjl 
1538*cb5caa98Sdjl /*ARGSUSED*/
1539*cb5caa98Sdjl void
1540*cb5caa98Sdjl nss_pdelete(void *buffer, size_t length)
1541*cb5caa98Sdjl {
1542*cb5caa98Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
1543*cb5caa98Sdjl 
1544*cb5caa98Sdjl 	/* unnecessary, kept for completeness */
1545*cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(pbuf);
1546*cb5caa98Sdjl }
1547