xref: /titanic_41/usr/src/cmd/nscd/nscd_switch.c (revision 940a40ea49c831201b0a8119547eb48e9a0ed2f8)
1cb5caa98Sdjl /*
2cb5caa98Sdjl  * CDDL HEADER START
3cb5caa98Sdjl  *
4cb5caa98Sdjl  * The contents of this file are subject to the terms of the
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * You may not use this file except in compliance with the License.
7cb5caa98Sdjl  *
8cb5caa98Sdjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cb5caa98Sdjl  * or http://www.opensolaris.org/os/licensing.
10cb5caa98Sdjl  * See the License for the specific language governing permissions
11cb5caa98Sdjl  * and limitations under the License.
12cb5caa98Sdjl  *
13cb5caa98Sdjl  * When distributing Covered Code, include this CDDL HEADER in each
14cb5caa98Sdjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cb5caa98Sdjl  * If applicable, add the following below this CDDL HEADER, with the
16cb5caa98Sdjl  * fields enclosed by brackets "[]" replaced with your own identifying
17cb5caa98Sdjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18cb5caa98Sdjl  *
19cb5caa98Sdjl  * CDDL HEADER END
20cb5caa98Sdjl  */
21cb620785Sraf 
22cb5caa98Sdjl /*
23d2ba247cSmichen  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24cb5caa98Sdjl  * Use is subject to license terms.
25cb5caa98Sdjl  */
26cb5caa98Sdjl 
27cb5caa98Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
28cb5caa98Sdjl 
29cb5caa98Sdjl #include <stdlib.h>	/* getenv() */
30cb5caa98Sdjl #include <assert.h>
31cb5caa98Sdjl #include <unistd.h>
32cb5caa98Sdjl #include <string.h>
33cb620785Sraf #include <pthread.h>
34cb5caa98Sdjl #include <dlfcn.h>
35cb5caa98Sdjl #include <nss_dbdefs.h>
36cb5caa98Sdjl #include <exec_attr.h>
37cb5caa98Sdjl #include <gssapi/gssapi.h>
38cb5caa98Sdjl #include "nscd_door.h"
39cb5caa98Sdjl #include "nscd_switch.h"
40cb5caa98Sdjl #include "nscd_log.h"
41cb5caa98Sdjl #include "nscd_frontend.h"
42cb5caa98Sdjl 
43cb5caa98Sdjl #pragma weak nss_search = _nss_search
44cb5caa98Sdjl #define	nss_search	_nss_search
45cb5caa98Sdjl 
46cb5caa98Sdjl extern rwlock_t nscd_smf_service_state_lock;
47cb5caa98Sdjl 
48cb5caa98Sdjl /* nscd id: main, forker, or child */
49cb5caa98Sdjl extern int _whoami;
50cb5caa98Sdjl 
51cb5caa98Sdjl static int
52cb5caa98Sdjl retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp)
53cb5caa98Sdjl {
54cb5caa98Sdjl 	if (res != NSS_TRYAGAIN && res !=  NSS_NISSERVDNS_TRYAGAIN) {
55cb5caa98Sdjl 		if (res == NSS_SUCCESS) {
56cb5caa98Sdjl 			__NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]);
57cb5caa98Sdjl 			__NSW_UNPAUSE_ACTION(
58cb5caa98Sdjl 			    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]);
59cb5caa98Sdjl 		}
60cb5caa98Sdjl 		return (0);
61cb5caa98Sdjl 	}
62cb5caa98Sdjl 
63cb5caa98Sdjl 	if ((res == NSS_TRYAGAIN &&
64cb5caa98Sdjl 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) ||
65cb5caa98Sdjl 	    (res == NSS_NISSERVDNS_TRYAGAIN &&
66cb5caa98Sdjl 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER))
67cb5caa98Sdjl 		return (1);
68cb5caa98Sdjl 
69cb5caa98Sdjl 	if (res == NSS_TRYAGAIN &&
70cb5caa98Sdjl 	    lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
71cb5caa98Sdjl 		if (n <= lkp->max_retries)
72cb5caa98Sdjl 			return (1);
73cb5caa98Sdjl 		else {
74cb5caa98Sdjl 			lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED;
75cb5caa98Sdjl 			return (0);
76cb5caa98Sdjl 		}
77cb5caa98Sdjl 
78cb5caa98Sdjl 	if (res == NSS_NISSERVDNS_TRYAGAIN &&
79cb5caa98Sdjl 	    lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
80cb5caa98Sdjl 		if (n <= lkp->max_retries)
81cb5caa98Sdjl 			return (1);
82cb5caa98Sdjl 		else {
83cb5caa98Sdjl 			lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] =
84cb5caa98Sdjl 			    __NSW_TRYAGAIN_PAUSED;
85cb5caa98Sdjl 			return (0);
86cb5caa98Sdjl 		}
87cb5caa98Sdjl 
88cb5caa98Sdjl 	return (0);
89cb5caa98Sdjl }
90cb5caa98Sdjl 
91cb620785Sraf static thread_key_t loopback_key = THR_ONCE_KEY;
92cb5caa98Sdjl typedef struct lb_key {
93cb5caa98Sdjl 	int		srci;
94cb5caa98Sdjl 	int		dbi;
95cb5caa98Sdjl 	int		fnum;
96cb5caa98Sdjl 	int		*lb_flagp;
97cb5caa98Sdjl } lb_key_t;
98cb5caa98Sdjl 
99cb5caa98Sdjl static int
100cb5caa98Sdjl set_loopback_key(lb_key_t *key) {
101cb5caa98Sdjl 
102cb620785Sraf 	int		rc;
103cb5caa98Sdjl 
104cb620785Sraf 	rc = thr_keycreate_once(&loopback_key, NULL);
105cb5caa98Sdjl 	/* set key if not already set */
106cb620785Sraf 	if (rc == 0 && pthread_getspecific(loopback_key) == NULL)
107cb5caa98Sdjl 		rc = thr_setspecific(loopback_key, key);
108cb5caa98Sdjl 
109cb5caa98Sdjl 	return (rc);
110cb5caa98Sdjl }
111cb5caa98Sdjl 
112cb5caa98Sdjl static lb_key_t *
113cb5caa98Sdjl get_loopback_key(void) {
114cb5caa98Sdjl 
115cb5caa98Sdjl 	char		*me = "get_loopback_key";
116cb5caa98Sdjl 	lb_key_t	*k = NULL;
117cb5caa98Sdjl 
118cb620785Sraf 	k = pthread_getspecific(loopback_key);
119cb5caa98Sdjl 
120cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
121cb620785Sraf 	(me, "get loopback key, key = %p\n", k);
122cb5caa98Sdjl 
123cb5caa98Sdjl 	return (k);
124cb5caa98Sdjl }
125cb5caa98Sdjl 
126cb5caa98Sdjl static void
127cb5caa98Sdjl clear_loopback_key(lb_key_t *key) {
128cb5caa98Sdjl 
129cb5caa98Sdjl 	char		*me = "clear_loopback_key";
130cb5caa98Sdjl 
131cb620785Sraf 	if (loopback_key != THR_ONCE_KEY && key != NULL) {
132cb5caa98Sdjl 		/*
133cb5caa98Sdjl 		 * key->lb_flagp points to the location of the
134cb5caa98Sdjl 		 * flag, check_flag, in the stack where it was
135cb5caa98Sdjl 		 * first set; clearing the flag tells that
136cb5caa98Sdjl 		 * stack the loopback error has been resolved
137cb5caa98Sdjl 		 */
138cb5caa98Sdjl 		*key->lb_flagp = 0;
139cb5caa98Sdjl 		(void) thr_setspecific(loopback_key, NULL);
140cb5caa98Sdjl 	}
141cb5caa98Sdjl 
142cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
143cb5caa98Sdjl 	(me, "key %p cleared\n", key);
144cb5caa98Sdjl }
145cb5caa98Sdjl 
146cb620785Sraf static thread_key_t initf_key = THR_ONCE_KEY;
147cb5caa98Sdjl 
148cb5caa98Sdjl static int
149cb5caa98Sdjl set_initf_key(void *pbuf) {
150cb5caa98Sdjl 
151cb620785Sraf 	int		rc;
152cb5caa98Sdjl 
153cb620785Sraf 	rc = thr_keycreate_once(&initf_key, NULL);
154cb5caa98Sdjl 	if (rc == 0)
155cb5caa98Sdjl 		rc = thr_setspecific(initf_key, pbuf);
156cb5caa98Sdjl 
157cb5caa98Sdjl 	return (rc);
158cb5caa98Sdjl }
159cb5caa98Sdjl 
160cb5caa98Sdjl static void *
161cb5caa98Sdjl get_initf_key(void) {
162cb5caa98Sdjl 
163cb5caa98Sdjl 	char		*me = "get_initf_key";
164cb5caa98Sdjl 	void		*pbuf;
165cb5caa98Sdjl 
166cb620785Sraf 	pbuf = pthread_getspecific(initf_key);
167cb5caa98Sdjl 
168cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
169cb620785Sraf 	(me, "got initf pbuf, key = %p\n", pbuf);
170cb5caa98Sdjl 
171cb5caa98Sdjl 	return (pbuf);
172cb5caa98Sdjl }
173cb5caa98Sdjl 
174cb5caa98Sdjl static void
175cb5caa98Sdjl clear_initf_key(void) {
176cb5caa98Sdjl 
177cb5caa98Sdjl 	char		*me = "clear_initf_key";
178cb5caa98Sdjl 
179cb5caa98Sdjl 	(void) thr_setspecific(initf_key, NULL);
180cb5caa98Sdjl 
181cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
182cb5caa98Sdjl 	(me, "initf pbuf cleared\n");
183cb5caa98Sdjl }
184cb5caa98Sdjl 
185cb5caa98Sdjl /*
186cb5caa98Sdjl  * Call the input initf function to extract the
187cb5caa98Sdjl  * NSS front end parameters and examine them to
188cb5caa98Sdjl  * determine if an NSS lookup is to be performed
189cb5caa98Sdjl  * on a regular or a pseudo (called from compat
190cb5caa98Sdjl  * backend) database. Then set the necessary
191cb5caa98Sdjl  * parameters for later data structures creation
192cb5caa98Sdjl  * and processing.
193cb5caa98Sdjl  */
194cb5caa98Sdjl static nscd_rc_t
195cb5caa98Sdjl getparams(
196cb5caa98Sdjl 	int			search_fnum,
197cb5caa98Sdjl 	nss_db_initf_t		initf,
198cb5caa98Sdjl 	nscd_nsw_params_t	*params)
199cb5caa98Sdjl {
200cb5caa98Sdjl 
201cb5caa98Sdjl 	nscd_rc_t	rc = NSCD_SUCCESS;
202cb5caa98Sdjl 	nss_db_params_t	*p;
203cb5caa98Sdjl 	int		j;
204cb5caa98Sdjl 	char		*dbn;
205cb5caa98Sdjl 	const char	*n;
206bee2e9ddSmichen 	char		*me = "getparams";
207cb5caa98Sdjl 
208cb5caa98Sdjl 	p = &params->p;
209cb5caa98Sdjl 	(void) memset(p, 0, sizeof (*p));
210cb5caa98Sdjl 	(*initf)(p);
211cb5caa98Sdjl 	params->dbi = -1;
212cb5caa98Sdjl 	params->cfgdbi = -1;
213cb5caa98Sdjl 	params->compati = -1;
214cb5caa98Sdjl 	params->dnsi = -1;
215cb5caa98Sdjl 
216cb5caa98Sdjl 	/* map database name to index */
217cb5caa98Sdjl 	n = p->name;
218cb5caa98Sdjl 	for (j = 0; j < NSCD_NUM_DB; j++) {
219cb5caa98Sdjl 		dbn = NSCD_NSW_DB_NAME(j);
220cb5caa98Sdjl 		if (*n != *dbn)
221cb5caa98Sdjl 			continue;
222cb5caa98Sdjl 		if (strcmp(n, dbn) == 0) {
223cb5caa98Sdjl 			params->dbi = j;
224cb5caa98Sdjl 			if (*n != 'h' && *n != 'i' && *n != 's' && *n != 'a')
225cb5caa98Sdjl 				break;
226cb5caa98Sdjl 			if (strcmp(n, NSS_DBNAM_HOSTS) == 0 &&
227cb5caa98Sdjl 			    search_fnum == NSS_DBOP_HOSTS_BYNAME)
228cb5caa98Sdjl 				params->dnsi = 0;
229cb5caa98Sdjl 			else if (strcmp(n, NSS_DBNAM_IPNODES) == 0 &&
230cb5caa98Sdjl 			    search_fnum == NSS_DBOP_IPNODES_BYNAME)
231cb5caa98Sdjl 				params->dnsi = 1;
232cb5caa98Sdjl 			else if (strcmp(n, NSS_DBNAM_SHADOW) == 0)
233cb5caa98Sdjl 				params->privdb = 1;
234cb5caa98Sdjl 			break;
235cb5caa98Sdjl 		}
236cb5caa98Sdjl 	}
237cb5caa98Sdjl 
238cb5caa98Sdjl 	/*
239cb5caa98Sdjl 	 * use the switch policy for passwd_compat or
240cb5caa98Sdjl 	 * group_compat?
241cb5caa98Sdjl 	 */
242cb5caa98Sdjl 	if (p->config_name != NULL) {
243cb5caa98Sdjl 
244cb5caa98Sdjl 		n = p->config_name;
245cb5caa98Sdjl 		for (j = 0; j < NSCD_NUM_DB; j++) {
246cb5caa98Sdjl 			dbn = NSCD_NSW_DB_NAME(j);
247cb5caa98Sdjl 			if (*n == *dbn) {
248cb5caa98Sdjl 				if (strcmp(n, dbn) == 0) {
249cb5caa98Sdjl 					params->cfgdbi = j;
250cb5caa98Sdjl 					break;
251cb5caa98Sdjl 				}
252cb5caa98Sdjl 			}
253cb5caa98Sdjl 		}
254cb5caa98Sdjl 	}
255cb5caa98Sdjl 
256cb5caa98Sdjl 	/* map the database name to the pseudo database index */
257cb5caa98Sdjl 	if (params->cfgdbi != -1) {
258cb5caa98Sdjl 		if (strstr(p->config_name, "_compat") != NULL) {
259cb5caa98Sdjl 			n = p->name;
260cb5caa98Sdjl 			for (j = params->cfgdbi; j < NSCD_NUM_DB; j++) {
261cb5caa98Sdjl 				dbn = NSCD_NSW_DB_NAME(j);
262cb5caa98Sdjl 				if (*n == *dbn) {
263cb5caa98Sdjl 					if (strcmp(n, dbn) == 0) {
264cb5caa98Sdjl 						params->compati = j;
265cb5caa98Sdjl 						break;
266cb5caa98Sdjl 					}
267cb5caa98Sdjl 				}
268cb5caa98Sdjl 			}
269cb5caa98Sdjl 		}
270cb5caa98Sdjl 	}
271cb5caa98Sdjl 
272bee2e9ddSmichen 	/*
273bee2e9ddSmichen 	 * if unsupported database, let caller determine what to do next
274bee2e9ddSmichen 	 */
275bee2e9ddSmichen 	if (params->dbi == -1) {
276bee2e9ddSmichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
277bee2e9ddSmichen 		(me, "unsupported database: %s\n", p->name);
278bee2e9ddSmichen 		return (NSCD_CFG_UNSUPPORTED_SWITCH_DB);
279bee2e9ddSmichen 	}
280bee2e9ddSmichen 
281cb5caa98Sdjl 	return (rc);
282cb5caa98Sdjl }
283cb5caa98Sdjl 
284cb5caa98Sdjl static void
285cb5caa98Sdjl nscd_initf(nss_db_params_t	*p)
286cb5caa98Sdjl {
287cb5caa98Sdjl 	nss_pheader_t		*pbuf;
288cb5caa98Sdjl 	nssuint_t		off;
289cb5caa98Sdjl 	nss_dbd_t		*pdbd;
290cb5caa98Sdjl 	char			*me = "nscd_initf";
291cb5caa98Sdjl 
292cb5caa98Sdjl 	pbuf = (nss_pheader_t *)get_initf_key();
293cb5caa98Sdjl 	if (pbuf == NULL) {
294cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
295cb5caa98Sdjl 		(me, "ERROR: initf key not set\n");
296cb5caa98Sdjl 		return;
297cb5caa98Sdjl 	}
298cb5caa98Sdjl 
299cb5caa98Sdjl 	if (pbuf->dbd_len <= sizeof (nss_dbd_t)) {
300cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
301cb5caa98Sdjl 		(me, "invalid db front params data ? dbd_len = %d\n",
302cb5caa98Sdjl 		    pbuf->dbd_len);
303cb5caa98Sdjl 		return;
304cb5caa98Sdjl 	}
305cb5caa98Sdjl 
306cb5caa98Sdjl 	off = pbuf->dbd_off;
307cb5caa98Sdjl 	pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off));
308cb5caa98Sdjl 
309cb5caa98Sdjl 	p->name = (char *)pdbd + pdbd->o_name;
310cb5caa98Sdjl 	p->config_name = (char *)pdbd + pdbd->o_config_name;
311cb5caa98Sdjl 	p->default_config = (char *)pdbd + pdbd->o_default_config;
312cb5caa98Sdjl 	p->flags = (enum nss_dbp_flags)pdbd->flags;
313cb5caa98Sdjl 	(void) memcpy(&p->private, &pbuf->nscdpriv, sizeof (p->private));
314cb5caa98Sdjl 
315cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
316cb5caa98Sdjl 	(me, "db frontend params: name =%s, config_name = %s, "
317cb5caa98Sdjl 	"default_config = %s, flags = %x\n", p->name,
318cb5caa98Sdjl 	    (p->config_name && *p->config_name != '\0' ?
319cb5caa98Sdjl 	    p->config_name : "<NOT SPECIFIED>"),
320cb5caa98Sdjl 	    (p->default_config && *p->default_config != '\0' ?
321cb5caa98Sdjl 	    p->default_config : "<NOT SPECIFIED>"),
322cb5caa98Sdjl 	    p->flags);
323cb5caa98Sdjl }
324cb5caa98Sdjl 
325cb5caa98Sdjl 
326cb5caa98Sdjl static void
327cb5caa98Sdjl trace_result(
328cb5caa98Sdjl 	int		dbi,
329cb5caa98Sdjl 	int		srci,
330cb5caa98Sdjl 	int		op,
331cb5caa98Sdjl 	nss_status_t	res,
332cb5caa98Sdjl 	nss_XbyY_args_t	*arg)
333cb5caa98Sdjl {
334cb5caa98Sdjl 	char	*res_str;
335cb5caa98Sdjl 	char	*src = "?";
336cb5caa98Sdjl 	char	*db = "?";
33718bdb8a7Smichen 	char	*data_str = "<NOT STRING FORMAT>";
33818bdb8a7Smichen 	int	data_len = 0;
33918bdb8a7Smichen 	char	*me = "trace_result";
340cb5caa98Sdjl 
341cb5caa98Sdjl 	switch (res) {
342cb5caa98Sdjl 	case NSS_SUCCESS:
343cb5caa98Sdjl 		res_str = "NSS_SUCCESS";
344cb5caa98Sdjl 		break;
345cb5caa98Sdjl 	case NSS_NOTFOUND:
346cb5caa98Sdjl 		res_str = "NSS_NOTFOUND";
347cb5caa98Sdjl 		break;
348cb5caa98Sdjl 	case NSS_UNAVAIL:
349cb5caa98Sdjl 		res_str = "NSS_UNAVAIL";
350cb5caa98Sdjl 		break;
351cb5caa98Sdjl 	case NSS_TRYAGAIN:
352cb5caa98Sdjl 		res_str = "NSS_TRYAGAIN";
353cb5caa98Sdjl 		break;
354cb5caa98Sdjl 	case NSS_NISSERVDNS_TRYAGAIN:
355cb5caa98Sdjl 		res_str = "NSS_NISSERVDNS_TRYAGAIN";
356cb5caa98Sdjl 		break;
357cb5caa98Sdjl 	default:
358cb5caa98Sdjl 		res_str = "UNKNOWN STATUS";
359cb5caa98Sdjl 		break;
360cb5caa98Sdjl 	}
361cb5caa98Sdjl 
362cb5caa98Sdjl 	if (dbi != -1)
363cb5caa98Sdjl 		db = NSCD_NSW_DB_NAME(dbi);
364cb5caa98Sdjl 	if (srci != -1)
365cb5caa98Sdjl 		src = NSCD_NSW_SRC_NAME(srci);
366cb5caa98Sdjl 
36718bdb8a7Smichen 	if (arg->buf.result == NULL) {
36818bdb8a7Smichen 		data_str = arg->buf.buffer;
36918bdb8a7Smichen 		data_len = arg->returnlen;
37018bdb8a7Smichen 	}
37118bdb8a7Smichen 
372cb5caa98Sdjl 	if (res == NSS_SUCCESS) {
373bf1e3beeSmichen 		_nscd_logit(me, "%s: database: %s, operation: %d, "
374bf1e3beeSmichen 		    "source: %s returned >>%s<<, length = %d\n",
37518bdb8a7Smichen 		    res_str, db, op, src, data_str, data_len);
376cb5caa98Sdjl 		return;
377cb5caa98Sdjl 	}
378cb5caa98Sdjl 
379bf1e3beeSmichen 	_nscd_logit(me, "%s: database: %s, operation: %d, source: %s, "
380*940a40eaSsm26363 	    "erange= %d, herrno: %s (%d)\n",
381*940a40eaSsm26363 	    res_str, db, op, src, arg->erange, hstrerror(arg->h_errno),
382*940a40eaSsm26363 	    arg->h_errno);
383cb5caa98Sdjl }
384cb5caa98Sdjl 
385cb5caa98Sdjl /*
386cb5caa98Sdjl  * Determine if a request should be done locally in the getXbyY caller's
3870dfdd7f3Smichen  * process. Return none zero if yes, 0 otherwise. This should be called
3880dfdd7f3Smichen  * before the switch engine steps through the backends/sources.
389bf1e3beeSmichen  * This function returns 1 if:
390cb5caa98Sdjl  *   -- the database is exec_attr and the search_flag is GET_ALL
391cb5caa98Sdjl  */
392cb5caa98Sdjl static int
393cb5caa98Sdjl try_local(
394cb5caa98Sdjl 	int			dbi,
395cb5caa98Sdjl 	void			*arg)
396cb5caa98Sdjl {
397cb5caa98Sdjl 	struct nss_XbyY_args	*ap = (struct nss_XbyY_args *)arg;
398cb5caa98Sdjl 	_priv_execattr		*ep;
399cb5caa98Sdjl 	int			rc = 0;
400cb5caa98Sdjl 	char			*me = "try_local";
401cb5caa98Sdjl 
402cb5caa98Sdjl 	if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_EXECATTR) == 0) {
403bf1e3beeSmichen 		if ((ep = ap->key.attrp) != NULL && ep->search_flag == GET_ALL)
404cb5caa98Sdjl 			rc = 1;
405cb5caa98Sdjl 	}
406cb5caa98Sdjl 
407cb5caa98Sdjl 	if (rc != 0) {
408cb5caa98Sdjl 
409cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
410cb5caa98Sdjl 		(me, "TRYLOCAL: exec_attr:GET_ALL\n");
411cb5caa98Sdjl 	}
412cb5caa98Sdjl 
413cb5caa98Sdjl 	return (rc);
414cb5caa98Sdjl }
415cb5caa98Sdjl 
4160dfdd7f3Smichen /*
4170dfdd7f3Smichen  * Determine if a request should be done locally in the getXbyY caller's
4180dfdd7f3Smichen  * process. Return none zero if yes, 0 otherwise. This should be called
4190dfdd7f3Smichen  * before the switch engine invokes any backend.
420bf1e3beeSmichen  * This function returns 1 if:
4210dfdd7f3Smichen  *   -- the database is shadow and the source is nisplus
4220dfdd7f3Smichen  */
4230dfdd7f3Smichen static int
4240dfdd7f3Smichen try_local2(
4250dfdd7f3Smichen 	int	dbi,
4260dfdd7f3Smichen 	int	srci)
4270dfdd7f3Smichen {
4280dfdd7f3Smichen 	int	rc = 0;
4290dfdd7f3Smichen 	char	*me = "try_local2";
4300dfdd7f3Smichen 
4310dfdd7f3Smichen 	if (*NSCD_NSW_DB_NAME(dbi) == 's' &&
4320dfdd7f3Smichen 	    strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_SHADOW) == 0) {
4330dfdd7f3Smichen 		if (strcmp(NSCD_NSW_SRC_NAME(srci), "nisplus") == 0)
4340dfdd7f3Smichen 			rc = 1;
4350dfdd7f3Smichen 	}
4360dfdd7f3Smichen 
4370dfdd7f3Smichen 	if (rc != 0) {
4380dfdd7f3Smichen 
4390dfdd7f3Smichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
4400dfdd7f3Smichen 		(me, "TRYLOCAL: database: shadow, source: nisplus\n");
4410dfdd7f3Smichen 	}
4420dfdd7f3Smichen 
4430dfdd7f3Smichen 	return (rc);
4440dfdd7f3Smichen }
4450dfdd7f3Smichen 
446cb5caa98Sdjl static nscd_rc_t
44718bdb8a7Smichen get_lib_func(void **handle, void **func, mutex_t *lock,
44818bdb8a7Smichen 	char *lib, char *name, void **func_p)
449c70a8a3bSmichen {
45018bdb8a7Smichen 	char	*me = "get_lib_func";
451c70a8a3bSmichen 	void	*sym;
452c70a8a3bSmichen 
45318bdb8a7Smichen 	if (func_p != NULL && *handle != NULL && *func != NULL) {
45418bdb8a7Smichen 		*func_p = *func;
455c70a8a3bSmichen 		return (NSCD_SUCCESS);
456c70a8a3bSmichen 	}
457c70a8a3bSmichen 
45818bdb8a7Smichen 	(void) mutex_lock(lock);
459c70a8a3bSmichen 
460c70a8a3bSmichen 	/* close the handle if requested */
461c70a8a3bSmichen 	if (func_p == NULL) {
46218bdb8a7Smichen 		if (*handle != NULL) {
46318bdb8a7Smichen 			(void) dlclose(*handle);
46418bdb8a7Smichen 			*handle = NULL;
46518bdb8a7Smichen 			*func = NULL;
466c70a8a3bSmichen 		}
46718bdb8a7Smichen 		(void) mutex_unlock(lock);
468c70a8a3bSmichen 		return (NSCD_SUCCESS);
469c70a8a3bSmichen 	}
470c70a8a3bSmichen 
47118bdb8a7Smichen 	if (*handle != NULL && *func != NULL) {
47218bdb8a7Smichen 		*func_p = *func;
47318bdb8a7Smichen 		(void) mutex_unlock(lock);
474c70a8a3bSmichen 		return (NSCD_SUCCESS);
475c70a8a3bSmichen 	}
476c70a8a3bSmichen 
47718bdb8a7Smichen 	if (*handle == NULL) {
47818bdb8a7Smichen 		*handle = dlopen(lib, RTLD_LAZY);
47918bdb8a7Smichen 		if (*handle == NULL) {
480bf1e3beeSmichen 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR)
48118bdb8a7Smichen 			(me, "unable to dlopen %s\n", lib);
48218bdb8a7Smichen 			(void) mutex_unlock(lock);
483c70a8a3bSmichen 			return (NSCD_CFG_DLOPEN_ERROR);
484c70a8a3bSmichen 		}
485c70a8a3bSmichen 	}
486c70a8a3bSmichen 
48718bdb8a7Smichen 	if ((sym = dlsym(*handle, name)) == NULL) {
488c70a8a3bSmichen 
489c70a8a3bSmichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR)
49018bdb8a7Smichen 		(me, "unable to find symbol %s:%s\n", lib, name);
49118bdb8a7Smichen 		(void) mutex_unlock(lock);
492c70a8a3bSmichen 		return (NSCD_CFG_DLSYM_ERROR);
493c70a8a3bSmichen 	} else {
49418bdb8a7Smichen 		*func_p = sym;
49518bdb8a7Smichen 		*func = sym;
496c70a8a3bSmichen 	}
497c70a8a3bSmichen 
49818bdb8a7Smichen 	(void) mutex_unlock(lock);
499c70a8a3bSmichen 	return (NSCD_SUCCESS);
500c70a8a3bSmichen }
501c70a8a3bSmichen 
50218bdb8a7Smichen static nscd_rc_t
50318bdb8a7Smichen get_libc_nss_search(void **func_p)
50418bdb8a7Smichen {
50518bdb8a7Smichen 	static void	*handle = NULL;
50618bdb8a7Smichen 	static void	*func = NULL;
50718bdb8a7Smichen 	static mutex_t	lock = DEFAULTMUTEX;
50818bdb8a7Smichen 
50918bdb8a7Smichen 	return (get_lib_func(&handle, &func, &lock,
51018bdb8a7Smichen 	    "libc.so", "nss_search", func_p));
51118bdb8a7Smichen }
51218bdb8a7Smichen 
51318bdb8a7Smichen static nscd_rc_t
51418bdb8a7Smichen get_gss_func(void **func_p)
51518bdb8a7Smichen {
51618bdb8a7Smichen 	static void	*handle = NULL;
51718bdb8a7Smichen 	static void	*func = NULL;
51818bdb8a7Smichen 	static mutex_t	lock = DEFAULTMUTEX;
51918bdb8a7Smichen 
52018bdb8a7Smichen 	return (get_lib_func(&handle, &func, &lock,
52118bdb8a7Smichen 	    "libgss.so", "gss_inquire_cred", func_p));
52218bdb8a7Smichen }
52318bdb8a7Smichen 
5244b22b933Srs200217 /*
5254b22b933Srs200217  * get_dns_funcs returns pointers to gethostbyname functions in the
5264b22b933Srs200217  * dynamically loaded nss_dns & nss_mdns modules that return host
5274b22b933Srs200217  * lookup results along with the TTL value in the DNS resource
5284b22b933Srs200217  * records. The dnsi parameter indicates whether the lookup database
5294b22b933Srs200217  * is hosts(0) or ipnodes(1). The srcname parameter identifies the DNS
5304b22b933Srs200217  * module: dns/mdns and the function returns the address of the specific
5314b22b933Srs200217  * gethostbyname function in func_p variable.
5324b22b933Srs200217  */
533c70a8a3bSmichen static nscd_rc_t
5344b22b933Srs200217 get_dns_funcs(int dnsi, nss_status_t (**func_p)(), const char *srcname)
535cb5caa98Sdjl {
5364b22b933Srs200217 	int		si;
53718bdb8a7Smichen 	void		**funcpp;
5384b22b933Srs200217 	static void	*handle[2] = { NULL, NULL };
5394b22b933Srs200217 	static mutex_t	func_lock[2] = { DEFAULTMUTEX, DEFAULTMUTEX };
5404b22b933Srs200217 	static void 	*func[2][2] = {{NULL, NULL}, {NULL, NULL}};
5414b22b933Srs200217 	static const char	*lib[2] = { "nss_dns.so.1", "nss_mdns.so.1" };
5424b22b933Srs200217 	static const char 	*func_name[2][2] =
5434b22b933Srs200217 		{{ "_nss_get_dns_hosts_name", "_nss_get_dns_ipnodes_name" },
5444b22b933Srs200217 		{ "_nss_get_mdns_hosts_name", "_nss_get_mdns_ipnodes_name" }};
545cb5caa98Sdjl 
5464b22b933Srs200217 	/* source index: 0 = dns, 1 = mdns */
5474b22b933Srs200217 	if (strcmp(srcname, "dns") == 0)
5484b22b933Srs200217 		si = 0;
5494b22b933Srs200217 	else
5504b22b933Srs200217 		si = 1;
5514b22b933Srs200217 
5524b22b933Srs200217 	/*
5534b22b933Srs200217 	 * function index (func[si][dnsi]):
5544b22b933Srs200217 	 * [0,0] = dns/hosts, [0,1] = dns/ipnodes,
5554b22b933Srs200217 	 * [1,0] = mdns/hosts, [1,1] = mdns/ipnodes
5564b22b933Srs200217 	 */
5574b22b933Srs200217 
55818bdb8a7Smichen 	if (dnsi < 0) { /* close handle */
55918bdb8a7Smichen 		funcpp = NULL;
5604b22b933Srs200217 		(void) mutex_lock(&func_lock[si]);
5614b22b933Srs200217 		func[si][0] = NULL;
5624b22b933Srs200217 		func[si][1] = NULL;
5634b22b933Srs200217 		(void) mutex_unlock(&func_lock[si]);
56418bdb8a7Smichen 	} else
56518bdb8a7Smichen 		funcpp = (void **)func_p;
566cb5caa98Sdjl 
56718bdb8a7Smichen 	return (get_lib_func(&handle[si], &func[si][dnsi], &func_lock[si],
56818bdb8a7Smichen 	    (char *)lib[si], (char *)func_name[si][dnsi], funcpp));
569cb5caa98Sdjl }
570cb5caa98Sdjl 
571cb5caa98Sdjl static nss_status_t
5724b22b933Srs200217 search_dns_withttl(nscd_sw_return_t *swret, const char *srcname, int dnsi)
573cb5caa98Sdjl {
574cb5caa98Sdjl 	nss_status_t	(*func)();
575cb5caa98Sdjl 	nss_status_t	res = NSS_UNAVAIL;
576cb5caa98Sdjl 	nscd_rc_t	rc;
577cb5caa98Sdjl 
578cb5caa98Sdjl 	swret->noarg = 0;
5794b22b933Srs200217 	if (strcmp(srcname, "dns") != 0 && strcmp(srcname, "mdns") != 0)
580cb5caa98Sdjl 		return (NSS_ERROR);
581cb5caa98Sdjl 
5824b22b933Srs200217 	rc = get_dns_funcs(dnsi, &func, srcname);
5834b22b933Srs200217 	if (rc == NSCD_SUCCESS) {
5844b22b933Srs200217 		/*
5854b22b933Srs200217 		 * data_len in the packed buf header may be changed
5864b22b933Srs200217 		 * by the dns or mdns backend, reset it just in
5874b22b933Srs200217 		 * case
5884b22b933Srs200217 		 */
5894b22b933Srs200217 		((nss_pheader_t *)swret->pbuf)->data_len =
5904b22b933Srs200217 		    swret->datalen;
591cb5caa98Sdjl 		res = (func)(NULL, &swret->pbuf, &swret->pbufsiz);
5924b22b933Srs200217 	}
593cb5caa98Sdjl 	return (res);
594cb5caa98Sdjl }
595cb5caa98Sdjl 
596cb5caa98Sdjl /*
597cb5caa98Sdjl  * Returns a flag to indicate if needs to fall back to the
598cb5caa98Sdjl  * main nscd when a per-user lookup failed with rc NSS_NOTFOUND.
599cb5caa98Sdjl  */
600cb5caa98Sdjl static int
601cb5caa98Sdjl set_fallback_flag(char *srcname, nss_status_t rc)
602cb5caa98Sdjl {
603cb5caa98Sdjl 	char	*me = "set_fallback_flag";
604cb5caa98Sdjl 	if (strcmp(srcname, "ldap") == 0 && rc == NSS_NOTFOUND) {
605cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
606cb5caa98Sdjl 		(me, "NSS_NOTFOUND (ldap): fallback to main nscd "
607cb5caa98Sdjl 		"may be needed\n");
608cb5caa98Sdjl 		return (1);
609cb5caa98Sdjl 	}
610cb5caa98Sdjl 	return (0);
611cb5caa98Sdjl }
612cb5caa98Sdjl 
613cb5caa98Sdjl nss_status_t
614cb5caa98Sdjl nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
615cb5caa98Sdjl 	void *search_args)
616cb5caa98Sdjl {
617cb5caa98Sdjl 	char			*me = "nss_search";
618cb5caa98Sdjl 	nss_status_t		res = NSS_UNAVAIL;
619cb5caa98Sdjl 	nscd_nsw_state_t	*s = NULL;
620cb5caa98Sdjl 	int			n_src;
621cb5caa98Sdjl 	unsigned int		status_vec = 0;
622cb5caa98Sdjl 	int			dbi, srci = -1;
623cb5caa98Sdjl 	int			check_loopback = 0;
624cb5caa98Sdjl 	int			state_thr = 0;
625cb5caa98Sdjl 	lb_key_t		key, *k = NULL;
626cb5caa98Sdjl 	nss_db_root_t		root_db;
627cb5caa98Sdjl 	nscd_nsw_params_t	params;
628cb5caa98Sdjl 	nscd_sw_return_t	*swret;
629cb5caa98Sdjl 
630cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
631cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, search_fnum = %d, "
632cb5caa98Sdjl 	    "search_args = %p\n", rootp, initf,
633cb5caa98Sdjl 	    search_fnum, search_args);
634cb5caa98Sdjl 
635cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_received_g++;
636cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g++;
637cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_queued_g++;
638cb5caa98Sdjl 
639cb5caa98Sdjl 	/* determine db index, cfg db index, etc */
640bee2e9ddSmichen 	if (getparams(search_fnum, initf, &params) ==
641bee2e9ddSmichen 	    NSCD_CFG_UNSUPPORTED_SWITCH_DB) {
642bee2e9ddSmichen 		/*
643bee2e9ddSmichen 		 * if unsupported database and the request is from the
644bee2e9ddSmichen 		 * the door, tell the door client to try it locally
645bee2e9ddSmichen 		 */
64618bdb8a7Smichen 		if (initf == nscd_initf) {
647bee2e9ddSmichen 			res = NSS_TRYLOCAL;
648bee2e9ddSmichen 			goto error_exit;
64918bdb8a7Smichen 		} else { /* otherwise, let libc:nss_search() handle it */
65018bdb8a7Smichen 			nss_status_t	(*func)();
65118bdb8a7Smichen 
65218bdb8a7Smichen 			if (get_libc_nss_search((void **)&func) ==
65318bdb8a7Smichen 			    NSCD_SUCCESS)
65418bdb8a7Smichen 				return ((func)(rootp, initf, search_fnum,
65518bdb8a7Smichen 				    search_args));
65618bdb8a7Smichen 			else
65718bdb8a7Smichen 				goto error_exit;
65818bdb8a7Smichen 		}
659bee2e9ddSmichen 	}
660cb5caa98Sdjl 	dbi = params.dbi;
661cb5caa98Sdjl 
662cb5caa98Sdjl 	/* get address of the switch engine return data area */
663cb5caa98Sdjl 	if (initf == nscd_initf) {
664cb5caa98Sdjl 		swret = (nscd_sw_return_t *)params.p.private;
665cb5caa98Sdjl 		swret->srci = -1;
666cb5caa98Sdjl 	} else {
667cb5caa98Sdjl 		swret = NULL;
668cb5caa98Sdjl 		params.dnsi = -1;
669cb5caa98Sdjl 	}
670cb5caa98Sdjl 
671cb5caa98Sdjl 	/*
67218bdb8a7Smichen 	 * for door request that should be processed by the client,
673cb5caa98Sdjl 	 * send it back with status NSS_TRYLOCAL
674cb5caa98Sdjl 	 */
67518bdb8a7Smichen 	if (initf == nscd_initf && try_local(dbi, search_args) == 1) {
676cb5caa98Sdjl 		res = NSS_TRYLOCAL;
677cb5caa98Sdjl 		goto error_exit;
678cb5caa98Sdjl 	}
679cb5caa98Sdjl 
680cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_received++;
681cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress++;
682cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_queued++;
683cb5caa98Sdjl 
684cb5caa98Sdjl 	/* if lookup not enabled, return NSS_UNAVAIL  */
685cb5caa98Sdjl 	if (!(NSCD_SW_CFG_G.enable_lookup_g == nscd_true &&
686cb5caa98Sdjl 	    NSCD_SW_CFG(dbi).enable_lookup == nscd_true)) {
687cb5caa98Sdjl 
688cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
689cb5caa98Sdjl 		(me, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi));
690cb5caa98Sdjl 
691cb5caa98Sdjl 		goto error_exit;
692cb5caa98Sdjl 	}
693cb5caa98Sdjl 
694cb5caa98Sdjl 	/* determine if loopback checking is configured */
695cb5caa98Sdjl 	if (NSCD_SW_CFG_G.enable_loopback_checking_g == nscd_true &&
696cb5caa98Sdjl 	    NSCD_SW_CFG(dbi).enable_loopback_checking == nscd_true) {
697cb5caa98Sdjl 		check_loopback = 1;
698cb5caa98Sdjl 
699cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
700cb5caa98Sdjl 		(me, "loopback checking enabled for %s\n",
701cb5caa98Sdjl 		    NSCD_NSW_DB_NAME(dbi));
702cb5caa98Sdjl 	}
703cb5caa98Sdjl 
704cb5caa98Sdjl 	if (check_loopback) {
705cb5caa98Sdjl 		k = get_loopback_key();
706cb5caa98Sdjl 		if (k != NULL) {
707cb5caa98Sdjl 			if (k->dbi != dbi || k->fnum != search_fnum) {
708cb5caa98Sdjl 				clear_loopback_key(k);
709cb5caa98Sdjl 				k = NULL;
710cb5caa98Sdjl 			}
711cb5caa98Sdjl 		}
712cb5caa98Sdjl 	}
713cb5caa98Sdjl 
714cb5caa98Sdjl 	if (s == 0) {
715cb5caa98Sdjl 		nscd_rc_t	rc;
716cb5caa98Sdjl 
717cb5caa98Sdjl 		if (check_loopback) {
718cb5caa98Sdjl 			rc = _nscd_get_nsw_state_thread(&root_db, &params);
719cb5caa98Sdjl 			state_thr = 1;
720cb5caa98Sdjl 		} else
721cb5caa98Sdjl 			rc = _nscd_get_nsw_state(&root_db, &params);
722cb5caa98Sdjl 
723cb5caa98Sdjl 		NSCD_SW_STATS_G.lookup_request_queued_g--;
724cb5caa98Sdjl 		NSCD_SW_STATS(dbi).lookup_request_queued--;
725cb5caa98Sdjl 
726cb5caa98Sdjl 		if (rc != NSCD_SUCCESS)
727cb5caa98Sdjl 				goto error_exit;
728cb5caa98Sdjl 
729cb5caa98Sdjl 		s = (nscd_nsw_state_t *)root_db.s;
730cb5caa98Sdjl 	}
731cb5caa98Sdjl 
732cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
733e37190e5Smichen 	(me, "database = %s, config = >>%s<<\n", NSCD_NSW_DB_NAME(dbi),
734cb5caa98Sdjl 	    (*s->nsw_cfg_p)->nsw_cfg_str);
735cb5caa98Sdjl 
736cb5caa98Sdjl 	for (n_src = 0;  n_src < s->max_src;  n_src++) {
73718bdb8a7Smichen 		nss_backend_t		*be = NULL;
73818bdb8a7Smichen 		nss_backend_op_t	funcp = NULL;
739cb5caa98Sdjl 		struct __nsw_lookup_v1	*lkp;
740cb5caa98Sdjl 		int			smf_state;
741cb5caa98Sdjl 		int			n_loop = 0;
742cb5caa98Sdjl 		int			max_retry = 10;
743cb5caa98Sdjl 
744cb5caa98Sdjl 		res = NSS_UNAVAIL;
745cb5caa98Sdjl 
746cb5caa98Sdjl 		if (n_src == 0)
747cb5caa98Sdjl 			lkp = s->config->lookups;
748cb5caa98Sdjl 		else
749cb5caa98Sdjl 			lkp = lkp->next;
750cb5caa98Sdjl 
751cb5caa98Sdjl 		/* set the number of max. retries */
752cb5caa98Sdjl 		if (lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
753cb5caa98Sdjl 			max_retry = lkp->max_retries;
754cb5caa98Sdjl 
755cb5caa98Sdjl 		srci = (*s->nsw_cfg_p)->src_idx[n_src];
756cb5caa98Sdjl 		if (swret != NULL)
757cb5caa98Sdjl 			swret->srci = srci;
758cb5caa98Sdjl 
759cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
760cb5caa98Sdjl 		(me, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci));
761cb5caa98Sdjl 
762cb5caa98Sdjl 		/* if no privilege to look up, skip */
763cb5caa98Sdjl 		if (params.privdb == 1 && swret != NULL &&
764cb5caa98Sdjl 		    strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 &&
765bf1e3beeSmichen 		    _nscd_check_client_read_priv() != 0) {
766bf1e3beeSmichen 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
767cb5caa98Sdjl 			(me, "no privilege to look up, skip source\n");
768cb5caa98Sdjl 
769cb5caa98Sdjl 			goto next_src;
770cb5caa98Sdjl 		}
771cb5caa98Sdjl 
772cb5caa98Sdjl 		/* get state of the (backend) client service */
773cb5caa98Sdjl 		smf_state = _nscd_get_smf_state(srci, dbi, 0);
774cb5caa98Sdjl 
775cb5caa98Sdjl 		/* stop if the source is one that should be TRYLOCAL */
776d2ba247cSmichen 		if (initf == nscd_initf &&	/* request is from the door */
777d2ba247cSmichen 		    (smf_state == NSCD_SVC_STATE_UNSUPPORTED_SRC ||
778d2ba247cSmichen 		    (smf_state == NSCD_SVC_STATE_FOREIGN_SRC &&
779d2ba247cSmichen 		    s->be_version_p[n_src] == NULL) ||
78018bdb8a7Smichen 		    (params.privdb && try_local2(dbi, srci) == 1))) {
781bf1e3beeSmichen 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
782cb5caa98Sdjl 			(me, "returning TRYLOCAL ... \n");
783cb5caa98Sdjl 			res = NSS_TRYLOCAL;
784cb5caa98Sdjl 			goto free_nsw_state;
785cb5caa98Sdjl 		}
786cb5caa98Sdjl 
787cb5caa98Sdjl 		if (check_loopback && k != NULL) {
788cb5caa98Sdjl 
789cb5caa98Sdjl 			if (k->srci == srci && k->dbi == dbi)
790cb5caa98Sdjl 				if (k->fnum == search_fnum) {
791cb5caa98Sdjl 
792cb5caa98Sdjl 					_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
793cb5caa98Sdjl 					    NSCD_LOG_LEVEL_DEBUG)
794cb5caa98Sdjl 					(me, "loopback detected: "
795cb5caa98Sdjl 					    "source = %s, database = %s "
796cb5caa98Sdjl 					    "search fnum = %d\n",
797cb5caa98Sdjl 					    NSCD_NSW_SRC_NAME(srci),
798cb5caa98Sdjl 					    NSCD_NSW_DB_NAME(dbi), search_fnum);
799cb5caa98Sdjl 
800cb5caa98Sdjl 				NSCD_SW_STATS_G.loopback_nsw_db_skipped_g++;
801cb5caa98Sdjl 				NSCD_SW_STATS(dbi).loopback_nsw_db_skipped++;
802cb5caa98Sdjl 					continue;
803cb5caa98Sdjl 				}
804cb5caa98Sdjl 		}
805cb5caa98Sdjl 
806cb5caa98Sdjl 		be = s->be[n_src];
807cb5caa98Sdjl 		if (be != NULL)
808cb5caa98Sdjl 			funcp = NSS_LOOKUP_DBOP(be, search_fnum);
809cb5caa98Sdjl 
810d2ba247cSmichen 		/* request could be from within nscd so check states again */
81118bdb8a7Smichen 		if (be == NULL || (params.dnsi < 0 && (funcp == NULL ||
81218bdb8a7Smichen 		    (smf_state != NSCD_SVC_STATE_UNINITED &&
813d2ba247cSmichen 		    smf_state != NSCD_SVC_STATE_UNSUPPORTED_SRC &&
814d2ba247cSmichen 		    smf_state != NSCD_SVC_STATE_FOREIGN_SRC &&
81518bdb8a7Smichen 		    smf_state < SCF_STATE_ONLINE)))) {
816cb5caa98Sdjl 
817cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
818cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG)
819cb5caa98Sdjl 			(me, "unable to look up source %s: be = %p, "
820cb5caa98Sdjl 			"smf state = %d, funcp = %p\n",
821cb5caa98Sdjl 			    NSCD_NSW_SRC_NAME(srci), be, smf_state, funcp);
822cb5caa98Sdjl 
823cb5caa98Sdjl 			goto next_src;
824cb5caa98Sdjl 		}
825cb5caa98Sdjl 
826cb5caa98Sdjl 		do {
827cb5caa98Sdjl 			/*
828cb5caa98Sdjl 			 * we can only retry max_retry times,
829cb5caa98Sdjl 			 * otherwise threads may get stuck in this
830cb5caa98Sdjl 			 * do-while loop forever
831cb5caa98Sdjl 			 */
832cb5caa98Sdjl 			if (n_loop > max_retry) {
833cb5caa98Sdjl 				if (swret != NULL)
834cb5caa98Sdjl 					res = NSS_TRYLOCAL;
835cb5caa98Sdjl 				goto free_nsw_state;
836cb5caa98Sdjl 			}
837cb5caa98Sdjl 
838cb5caa98Sdjl 			/*
839cb5caa98Sdjl 			 * set up to prevent loopback
840cb5caa98Sdjl 			 */
841cb5caa98Sdjl 			if (check_loopback && k == NULL) {
842cb5caa98Sdjl 				key.srci = srci;
843cb5caa98Sdjl 				key.dbi = dbi;
844cb5caa98Sdjl 				key.fnum = search_fnum;
845cb5caa98Sdjl 				key.lb_flagp = &check_loopback;
846cb5caa98Sdjl 				(void) set_loopback_key(&key);
847cb5caa98Sdjl 				k = &key;
848cb5caa98Sdjl 			}
849cb5caa98Sdjl 
850cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
851cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG)
852cb5caa98Sdjl 			(me, "looking up source = %s, loop# = %d \n",
853cb5caa98Sdjl 			    NSCD_NSW_SRC_NAME(srci), n_loop);
854cb5caa98Sdjl 
855cb5caa98Sdjl 			/*
856cb5caa98Sdjl 			 * search the backend, if hosts lookups,
857cb5caa98Sdjl 			 * try to get the hosts data with ttl first
858cb5caa98Sdjl 			 */
859cb5caa98Sdjl 			if (params.dnsi >= 0) {
860cb5caa98Sdjl 				res = search_dns_withttl(swret,
861bf1e3beeSmichen 				    NSCD_NSW_SRC_NAME(srci), params.dnsi);
862cb5caa98Sdjl 				/*
863cb5caa98Sdjl 				 * if not able to get ttl, fall back
864cb5caa98Sdjl 				 * to the regular backend call
865cb5caa98Sdjl 				 */
866cb5caa98Sdjl 				if (res == NSS_ERROR)
867cb5caa98Sdjl 					res = (*funcp)(be, search_args);
868cb5caa98Sdjl 				else {
869cb5caa98Sdjl 					/*
870cb5caa98Sdjl 					 * status/result are in the
871cb5caa98Sdjl 					 * packed buffer, not
872cb5caa98Sdjl 					 * search_args
873cb5caa98Sdjl 					 */
874cb5caa98Sdjl 					swret->noarg = 1;
875cb5caa98Sdjl 				}
876cb5caa98Sdjl 			} else
877cb5caa98Sdjl 				res = (*funcp)(be, search_args);
878cb5caa98Sdjl 			if (swret != NULL)
879cb5caa98Sdjl 				swret->errnum = errno;
880cb5caa98Sdjl 
881cb5caa98Sdjl 			/*
882cb5caa98Sdjl 			 * backend is not up, check and update the
883cb5caa98Sdjl 			 * smf state table
884cb5caa98Sdjl 			 */
885cb5caa98Sdjl 			if (res == NSS_UNAVAIL)
886cb5caa98Sdjl 				(void) _nscd_get_smf_state(srci, dbi, 1);
887cb5caa98Sdjl 
888cb5caa98Sdjl 			/*
889cb5caa98Sdjl 			 * may need to fall back to use the main nscd
890cb5caa98Sdjl 			 * if per-user lookup
891cb5caa98Sdjl 			 */
892cb5caa98Sdjl 			if (_whoami == NSCD_CHILD && swret != NULL)
893cb5caa98Sdjl 				swret->fallback = set_fallback_flag(
894cb5caa98Sdjl 				    NSCD_NSW_SRC_NAME(srci), res);
895cb5caa98Sdjl 
896cb5caa98Sdjl 			_NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE,
897cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG) {
898cb5caa98Sdjl 
899cb5caa98Sdjl 				/*
900cb5caa98Sdjl 				 * set up to trace the result/status
901cb5caa98Sdjl 				 * of the dns/ttl lookup
902cb5caa98Sdjl 				 */
903cb5caa98Sdjl 				if (swret != NULL && swret->noarg == 1) {
904cb5caa98Sdjl 					nss_pheader_t *phdr;
905cb5caa98Sdjl 					struct nss_XbyY_args *arg;
906cb5caa98Sdjl 					arg = (struct nss_XbyY_args *)
907cb5caa98Sdjl 					    search_args;
908cb5caa98Sdjl 					phdr = (nss_pheader_t *)swret->pbuf;
909cb5caa98Sdjl 					arg->buf.buffer = (char *)phdr +
910cb5caa98Sdjl 					    phdr->data_off;
911cb5caa98Sdjl 					arg->returnlen = phdr->data_len;
912cb5caa98Sdjl 					if (phdr->p_errno == ERANGE)
913cb5caa98Sdjl 						arg->erange = 1;
914cb5caa98Sdjl 					arg->h_errno = phdr->p_herrno;
915cb5caa98Sdjl 				}
916cb5caa98Sdjl 
917cb5caa98Sdjl 				trace_result(dbi, srci, search_fnum, res,
918cb5caa98Sdjl 				    (nss_XbyY_args_t *)search_args);
919cb5caa98Sdjl 			}
920cb5caa98Sdjl 
921cb5caa98Sdjl 			n_loop++;
922cb5caa98Sdjl 		} while (retry_test(res, n_loop, lkp));
923cb5caa98Sdjl 
924cb5caa98Sdjl 		next_src:
925cb5caa98Sdjl 
926cb5caa98Sdjl 		status_vec |= (1 << res);
927cb5caa98Sdjl 
928cb5caa98Sdjl 		if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) {
929cb5caa98Sdjl 			break;
930cb5caa98Sdjl 		}
931cb5caa98Sdjl 	}
932cb5caa98Sdjl 
933cb5caa98Sdjl 	free_nsw_state:
934cb5caa98Sdjl 
935cb5caa98Sdjl 	if (state_thr == 1)
936cb5caa98Sdjl 		_nscd_put_nsw_state_thread(s);
937cb5caa98Sdjl 	else
938cb5caa98Sdjl 		_nscd_put_nsw_state(s);
939cb5caa98Sdjl 	if (check_loopback && k != NULL)
940cb5caa98Sdjl 		clear_loopback_key(k);
941cb5caa98Sdjl 
942cb5caa98Sdjl 	if (res != NSS_SUCCESS)
943cb5caa98Sdjl 		goto error_exit;
944cb5caa98Sdjl 
945cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_succeeded_g++;
946cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_succeeded++;
947cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g--;
948cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress--;
949cb5caa98Sdjl 
950cb5caa98Sdjl 	return (NSS_SUCCESS);
951cb5caa98Sdjl 
952cb5caa98Sdjl 	error_exit:
953cb5caa98Sdjl 
954cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_failed_g++;
955cb5caa98Sdjl 	NSCD_SW_STATS_G.lookup_request_in_progress_g--;
956cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_failed++;
957cb5caa98Sdjl 	NSCD_SW_STATS(dbi).lookup_request_in_progress--;
958cb5caa98Sdjl 
959cb5caa98Sdjl 	return (res);
960cb5caa98Sdjl }
961cb5caa98Sdjl 
962cb5caa98Sdjl 
963cb5caa98Sdjl /* ===> get/set/endent */
964cb5caa98Sdjl 
965cb5caa98Sdjl static void		nss_setent_u(nss_db_root_t *,
966cb5caa98Sdjl 				    nss_db_initf_t,
967cb5caa98Sdjl 				    nss_getent_t *);
968cb5caa98Sdjl static nss_status_t	nss_getent_u(nss_db_root_t *,
969cb5caa98Sdjl 				    nss_db_initf_t,
970cb5caa98Sdjl 				    nss_getent_t *,
971cb5caa98Sdjl 				    void *);
972cb5caa98Sdjl static void		nss_endent_u(nss_db_root_t *,
973cb5caa98Sdjl 				    nss_db_initf_t,
974cb5caa98Sdjl 				    nss_getent_t *);
975cb5caa98Sdjl 
976cb5caa98Sdjl void
977cb5caa98Sdjl nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf,
978cb5caa98Sdjl 	nss_getent_t *contextpp)
979cb5caa98Sdjl {
980cb5caa98Sdjl 	if (contextpp == 0)
981cb5caa98Sdjl 		return;
982cb5caa98Sdjl 	nss_setent_u(rootp, initf, contextpp);
983cb5caa98Sdjl }
984cb5caa98Sdjl 
985cb5caa98Sdjl nss_status_t
986cb5caa98Sdjl nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp,
987cb5caa98Sdjl 	void *args)
988cb5caa98Sdjl {
989cb5caa98Sdjl 	nss_status_t		status;
990cb5caa98Sdjl 
991cb5caa98Sdjl 	if (contextpp == 0) {
992cb5caa98Sdjl 		return (NSS_UNAVAIL);
993cb5caa98Sdjl 	}
994cb5caa98Sdjl 	status = nss_getent_u(rootp, initf, contextpp, args);
995cb5caa98Sdjl 	return (status);
996cb5caa98Sdjl }
997cb5caa98Sdjl 
998cb5caa98Sdjl void
999cb5caa98Sdjl nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf,
1000cb5caa98Sdjl 	nss_getent_t *contextpp)
1001cb5caa98Sdjl {
1002cb5caa98Sdjl 	if (contextpp == 0)
1003cb5caa98Sdjl 		return;
1004cb5caa98Sdjl 	nss_endent_u(rootp, initf, contextpp);
1005cb5caa98Sdjl }
1006cb5caa98Sdjl 
1007cb5caa98Sdjl /*ARGSUSED*/
1008cb5caa98Sdjl static void
1009cb5caa98Sdjl end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp)
1010cb5caa98Sdjl {
1011cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1012cb5caa98Sdjl 	nscd_nsw_state_t	*s;
1013cb5caa98Sdjl 	nss_backend_t		*be;
1014cb5caa98Sdjl 	int			n_src;
1015cb5caa98Sdjl 
1016cb5caa98Sdjl 	ctx = (nscd_getent_context_t *)contextp;
1017cb5caa98Sdjl 	s = ctx->nsw_state;
1018cb5caa98Sdjl 	n_src = ctx->n_src;
1019cb5caa98Sdjl 	be = ctx->be;
1020cb5caa98Sdjl 
1021cb5caa98Sdjl 	if (s != 0) {
1022cb5caa98Sdjl 		if (n_src < s->max_src && be != 0) {
1023cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
1024cb5caa98Sdjl 			ctx->be = 0;  /* Should be unnecessary, but hey */
1025cb5caa98Sdjl 		}
1026cb5caa98Sdjl 	}
1027cb5caa98Sdjl 	ctx->n_src = 0;
1028cb5caa98Sdjl }
1029cb5caa98Sdjl 
1030cb5caa98Sdjl static void
1031cb5caa98Sdjl nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
1032cb5caa98Sdjl 	nss_getent_t *contextpp)
1033cb5caa98Sdjl {
1034cb5caa98Sdjl 	char			*me = "nss_setent_u";
1035cb5caa98Sdjl 	nscd_nsw_state_t	*s;
1036cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
1037cb5caa98Sdjl 	nscd_nsw_params_t	params;
1038cb5caa98Sdjl 	nss_db_root_t		root;
1039cb5caa98Sdjl 	nss_backend_t		*be;
1040cb5caa98Sdjl 	int			n_src, i;
1041cb5caa98Sdjl 	nscd_sw_return_t	*swret = NULL;
1042cb5caa98Sdjl 
1043cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1044cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p \n",
1045cb5caa98Sdjl 	    rootp, initf, contextpp);
1046cb5caa98Sdjl 
1047bee2e9ddSmichen 	/*
1048bee2e9ddSmichen 	 * Get the nsw db index via the initf function. If unsupported
1049bee2e9ddSmichen 	 * database, no need to continue
1050bee2e9ddSmichen 	 */
1051bee2e9ddSmichen 	if (getparams(-1, initf, &params) == NSCD_CFG_UNSUPPORTED_SWITCH_DB)
1052bee2e9ddSmichen 		return;
1053cb5caa98Sdjl 
1054cb5caa98Sdjl 	/* get address of the switch engine return data area */
1055cb5caa98Sdjl 	if (initf == nscd_initf)
1056cb5caa98Sdjl 		swret = (nscd_sw_return_t *)params.p.private;
1057cb5caa98Sdjl 
1058cb5caa98Sdjl 	/* if no privilege to look up, return */
1059cb5caa98Sdjl 	if (params.privdb == 1 && swret != NULL &&
1060bf1e3beeSmichen 	    _nscd_check_client_read_priv() != 0) {
1061cb5caa98Sdjl 
1062cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1063cb5caa98Sdjl 		(me, "no privilege \n");
1064cb5caa98Sdjl 		return;
1065cb5caa98Sdjl 	}
1066cb5caa98Sdjl 
1067cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1068cb5caa98Sdjl 		if ((_nscd_get_getent_ctx(contextpp, &params)) !=
1069cb5caa98Sdjl 		    NSCD_SUCCESS) {
1070cb5caa98Sdjl 			return;
1071cb5caa98Sdjl 		}
1072cb5caa98Sdjl 		contextp = (nscd_getent_context_t *)contextpp->ctx;
1073cb5caa98Sdjl 	}
1074cb5caa98Sdjl 	s = contextp->nsw_state;
1075cb5caa98Sdjl 
1076cb5caa98Sdjl 	if (s == 0) {
1077cb5caa98Sdjl 		if (_nscd_get_nsw_state(&root, &params) !=
1078cb5caa98Sdjl 		    NSCD_SUCCESS) {
1079cb5caa98Sdjl 			return;
1080cb5caa98Sdjl 		}
1081cb5caa98Sdjl 		s = (nscd_nsw_state_t *)root.s;
1082cb5caa98Sdjl 		contextp->nsw_state = s;
1083cb5caa98Sdjl 
1084cb5caa98Sdjl 	} else {
1085cb5caa98Sdjl 		s	= contextp->nsw_state;
1086cb5caa98Sdjl 		n_src	= contextp->n_src;
1087cb5caa98Sdjl 		be	= contextp->be;
1088cb5caa98Sdjl 		if (n_src == 0 && be != 0) {
1089cb5caa98Sdjl 			/*
1090cb5caa98Sdjl 			 * Optimization:  don't do endent, don't change
1091cb5caa98Sdjl 			 *   backends, just do the setent.  Look Ma, no locks
1092cb5caa98Sdjl 			 *   (nor any context that needs updating).
1093cb5caa98Sdjl 			 */
1094cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
1095cb5caa98Sdjl 			return;
1096cb5caa98Sdjl 		}
1097cb5caa98Sdjl 		if (n_src < s->max_src && be != 0) {
1098cb5caa98Sdjl 			(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
1099cb5caa98Sdjl 			contextp->be = 0;	/* Play it safe */
1100cb5caa98Sdjl 		}
1101cb5caa98Sdjl 	}
1102cb5caa98Sdjl 	for (n_src = 0, be = 0; n_src < s->max_src &&
1103cb5caa98Sdjl 	    (be = s->be[n_src]) == 0; n_src++) {
1104cb5caa98Sdjl 		;
1105cb5caa98Sdjl 	}
1106cb5caa98Sdjl 
1107cb5caa98Sdjl 	contextp->n_src	= n_src;
1108cb5caa98Sdjl 	contextp->be	= be;
1109cb5caa98Sdjl 
1110cb5caa98Sdjl 	if (be == 0) {
1111cb5caa98Sdjl 		/* Things are broken enough that we can't do setent/getent */
1112cb5caa98Sdjl 		nss_endent_u(rootp, initf, contextpp);
1113cb5caa98Sdjl 		return;
1114cb5caa98Sdjl 	}
1115cb5caa98Sdjl 
1116cb5caa98Sdjl 	/*
1117cb5caa98Sdjl 	 * make sure all the backends are supported
1118cb5caa98Sdjl 	 */
1119cb5caa98Sdjl 	for (i = 0; i < s->max_src; i++) {
1120cb5caa98Sdjl 		int	st, srci;
1121cb5caa98Sdjl 
1122d2ba247cSmichen 		if (s->be[i] == NULL)
1123d2ba247cSmichen 			continue;
1124d2ba247cSmichen 
1125cb5caa98Sdjl 		srci = (*s->nsw_cfg_p)->src_idx[i];
1126cb5caa98Sdjl 		st = _nscd_get_smf_state(srci, params.dbi, 1);
1127d2ba247cSmichen 		if (st == NSCD_SVC_STATE_UNSUPPORTED_SRC ||
1128d2ba247cSmichen 		    (st == NSCD_SVC_STATE_FOREIGN_SRC &&
1129d2ba247cSmichen 		    s->be_version_p[i] == NULL) ||
1130d2ba247cSmichen 		    st == NSCD_SVC_STATE_UNINITED ||
1131d2ba247cSmichen 		    (params.privdb &&
11320dfdd7f3Smichen 		    try_local2(params.dbi, srci) == 1)) {
1133cb5caa98Sdjl 			nss_endent_u(rootp, initf, contextpp);
1134cb5caa98Sdjl 
1135cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1136cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG)
1137cb5caa98Sdjl 			(me, "backend (%s) not available (state = %d)\n",
1138cb5caa98Sdjl 			    NSCD_NSW_SRC_NAME(srci), st);
1139cb5caa98Sdjl 
1140cb5caa98Sdjl 			return;
1141cb5caa98Sdjl 		}
1142cb5caa98Sdjl 	}
1143cb5caa98Sdjl 
1144cb5caa98Sdjl 	(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
1145cb5caa98Sdjl }
1146cb5caa98Sdjl 
1147cb5caa98Sdjl nss_status_t
1148cb5caa98Sdjl nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
1149cb5caa98Sdjl 	nss_getent_t *contextpp, void *args)
1150cb5caa98Sdjl {
1151cb5caa98Sdjl 	char			*me = "nss_getent_u";
1152cb5caa98Sdjl 	nscd_nsw_state_t	*s;
1153cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
1154cb5caa98Sdjl 	int			n_src;
1155cb5caa98Sdjl 	nss_backend_t		*be;
1156cb5caa98Sdjl 
1157cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1158cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p, args = %p\n",
1159cb5caa98Sdjl 	    rootp, initf, contextpp, args);
1160cb5caa98Sdjl 
1161cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1162cb5caa98Sdjl 		nss_setent_u(rootp, initf, contextpp);
1163cb5caa98Sdjl 		if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1164cb5caa98Sdjl 			/* Give up */
1165cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1166cb5caa98Sdjl 			    NSCD_LOG_LEVEL_ERROR)
1167cb5caa98Sdjl 			(me, "not able to obtain getent context ... give up\n");
1168cb5caa98Sdjl 
1169cb5caa98Sdjl 			return (NSS_UNAVAIL);
1170cb5caa98Sdjl 		}
1171cb5caa98Sdjl 	}
1172cb5caa98Sdjl 
1173cb5caa98Sdjl 	s	= contextp->nsw_state;
1174cb5caa98Sdjl 	n_src	= contextp->n_src;
1175cb5caa98Sdjl 	be	= contextp->be;
1176cb5caa98Sdjl 
1177cb5caa98Sdjl 	if (s == 0) {
1178cb5caa98Sdjl 		/*
1179cb5caa98Sdjl 		 * We've done an end_iter() and haven't done nss_setent()
1180cb5caa98Sdjl 		 * or nss_endent() since;  we should stick in this state
1181cb5caa98Sdjl 		 * until the caller invokes one of those two routines.
1182cb5caa98Sdjl 		 */
1183cb5caa98Sdjl 		return (NSS_SUCCESS);
1184cb5caa98Sdjl 	}
1185cb5caa98Sdjl 
1186cb5caa98Sdjl 	while (n_src < s->max_src) {
1187cb5caa98Sdjl 		nss_status_t		res;
1188cb5caa98Sdjl 		struct __nsw_lookup_v1	*lkp = NULL;
1189cb5caa98Sdjl 		int			n;
1190cb5caa98Sdjl 
1191cb5caa98Sdjl 		/* get the nsw config for the current source */
1192cb5caa98Sdjl 		lkp = s->config->lookups;
1193cb5caa98Sdjl 		for (n = 0; n < n_src; n++)
1194cb5caa98Sdjl 			lkp = lkp->next;
1195cb5caa98Sdjl 
1196cb5caa98Sdjl 		if (be == 0) {
1197cb5caa98Sdjl 			/* If it's null it's a bug, but let's play safe */
1198cb5caa98Sdjl 			res = NSS_UNAVAIL;
1199cb5caa98Sdjl 		} else {
1200cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1201cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG)
1202cb5caa98Sdjl 			(me, "database: %s, backend: %s, nsswitch config: %s\n",
1203cb5caa98Sdjl 			    NSCD_NSW_DB_NAME(s->dbi),
1204cb5caa98Sdjl 			    lkp->service_name,
1205cb5caa98Sdjl 			    (*s->nsw_cfg_p)->nsw_cfg_str);
1206cb5caa98Sdjl 
1207cb5caa98Sdjl 			res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args);
1208cb5caa98Sdjl 		}
1209cb5caa98Sdjl 
1210cb5caa98Sdjl 		if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) {
1211cb5caa98Sdjl 			if (res != __NSW_SUCCESS) {
1212cb5caa98Sdjl 				end_iter_u(rootp,
1213cb5caa98Sdjl 				    (struct nss_getent_context *)contextp);
1214cb5caa98Sdjl 			}
1215cb5caa98Sdjl 			return (res);
1216cb5caa98Sdjl 		}
1217cb5caa98Sdjl 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
1218cb5caa98Sdjl 		do {
1219cb5caa98Sdjl 			n_src++;
1220cb5caa98Sdjl 		} while (n_src < s->max_src &&
1221cb5caa98Sdjl 		    (be = s->be[n_src]) == 0);
1222cb5caa98Sdjl 		if (be == 0) {
1223cb5caa98Sdjl 			/*
1224cb5caa98Sdjl 			 * This is the case where we failed to get the backend
1225cb5caa98Sdjl 			 * for the last source. We exhausted all sources.
1226cb5caa98Sdjl 			 */
1227cb5caa98Sdjl 			nss_endent_u(rootp, initf, contextpp);
12282802e980Smichen 			return (NSS_NOTFOUND);
1229cb5caa98Sdjl 		}
1230cb5caa98Sdjl 		contextp->n_src	= n_src;
1231cb5caa98Sdjl 		contextp->be	= be;
1232cb5caa98Sdjl 		(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
1233cb5caa98Sdjl 	}
1234cb5caa98Sdjl 	/* Got to the end of the sources without finding another entry */
1235cb5caa98Sdjl 	end_iter_u(rootp, (struct nss_getent_context *)contextp);
1236cb5caa98Sdjl 	return (NSS_SUCCESS);
1237cb5caa98Sdjl 	/* success is either a successful entry or end of the sources */
1238cb5caa98Sdjl }
1239cb5caa98Sdjl 
1240cb5caa98Sdjl /*ARGSUSED*/
1241cb5caa98Sdjl void
1242cb5caa98Sdjl nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
1243cb5caa98Sdjl 	nss_getent_t *contextpp)
1244cb5caa98Sdjl {
1245cb5caa98Sdjl 	char			*me = "nss_endent_u";
1246cb5caa98Sdjl 	nscd_getent_context_t	*contextp;
1247cb5caa98Sdjl 
1248cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1249cb5caa98Sdjl 	(me, "rootp = %p, initf = %p, contextpp = %p \n",
1250cb5caa98Sdjl 	    rootp, initf, contextpp);
1251cb5caa98Sdjl 
1252cb5caa98Sdjl 	if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) {
1253cb5caa98Sdjl 		/* nss_endent() on an unused context is a no-op */
1254cb5caa98Sdjl 		return;
1255cb5caa98Sdjl 	}
1256cb5caa98Sdjl 	end_iter_u(rootp, (struct nss_getent_context *)contextp);
1257cb5caa98Sdjl 	_nscd_put_getent_ctx(contextp);
1258cb5caa98Sdjl 	contextpp->ctx = NULL;
1259cb5caa98Sdjl }
1260cb5caa98Sdjl 
1261cb5caa98Sdjl /*
1262cb5caa98Sdjl  * _nss_db_state_destr() and nss_delete() do nothing in nscd
1263cb5caa98Sdjl  * but is needed to make the caller (below nscd) happy
1264cb5caa98Sdjl  */
1265cb5caa98Sdjl /*ARGSUSED*/
1266cb5caa98Sdjl void
1267cb5caa98Sdjl _nss_db_state_destr(struct nss_db_state *s)
1268cb5caa98Sdjl {
1269cb5caa98Sdjl 	/* nsw state in nscd is always reused, so do nothing here */
1270cb5caa98Sdjl }
1271cb5caa98Sdjl 
1272cb5caa98Sdjl /*ARGSUSED*/
1273cb5caa98Sdjl void
1274cb5caa98Sdjl nss_delete(nss_db_root_t *rootp)
1275cb5caa98Sdjl {
1276cb5caa98Sdjl 	/*
1277cb5caa98Sdjl 	 * the only resource kept tracked by the nss_db_root_t
1278cb5caa98Sdjl 	 * is the nsw state which is always reused and no need
1279cb5caa98Sdjl 	 * to be freed. So just return.
1280cb5caa98Sdjl 	 */
1281cb5caa98Sdjl }
1282cb5caa98Sdjl 
1283cb5caa98Sdjl /*
1284cb5caa98Sdjl  * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent()
1285cb5caa98Sdjl  * buffers switch entry points
1286cb5caa98Sdjl  */
1287cb5caa98Sdjl 
1288cb5caa98Sdjl /*
1289cb5caa98Sdjl  * nss_psearch opens a packed structure header, assembles a local
1290cb5caa98Sdjl  * nss_XbyY_args_t structure and calls the local copy of nss_search.
1291cb5caa98Sdjl  * The return data is assembled in "files native format" in the
1292cb5caa98Sdjl  * return buffer location.  Status if packed back up with the buffer
1293cb5caa98Sdjl  * and the whole wad is returned to the cache or the client.
1294cb5caa98Sdjl  */
1295cb5caa98Sdjl 
1296cb5caa98Sdjl void
1297cb5caa98Sdjl nss_psearch(void *buffer, size_t length)
1298cb5caa98Sdjl {
1299cb5caa98Sdjl 	/* inputs */
1300cb5caa98Sdjl 	nss_db_initf_t		initf;
1301cb5caa98Sdjl 	int			dbop;
1302cb5caa98Sdjl 	int			rc;
1303cb5caa98Sdjl 	nss_XbyY_args_t		arg;
1304cb5caa98Sdjl 	nss_status_t		status;
1305cb5caa98Sdjl 	nscd_sw_return_t	swret = { 0 }, *swrp = &swret;
1306cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1307cb5caa98Sdjl 	char			*me = "nss_psearch";
1308cb5caa98Sdjl 
1309cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1310cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1311cb5caa98Sdjl 	}
1312cb5caa98Sdjl 
1313cb5caa98Sdjl 	status = nss_packed_arg_init(buffer, length,
1314cb5caa98Sdjl 	    NULL, &initf, &dbop, &arg);
1315cb5caa98Sdjl 	if (status != NSS_SUCCESS) {
1316cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, status, -1);
1317cb5caa98Sdjl 	}
1318cb5caa98Sdjl 
1319cb5caa98Sdjl 	/*
1320cb5caa98Sdjl 	 * pass the address of the return data area
1321cb5caa98Sdjl 	 * for the switch engine to return its own data
1322cb5caa98Sdjl 	 */
1323cb5caa98Sdjl 	(void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp));
1324cb5caa98Sdjl 	swret.pbuf = buffer;
1325cb5caa98Sdjl 	swret.pbufsiz = length;
13264b22b933Srs200217 	swret.datalen = pbuf->data_len;
1327cb5caa98Sdjl 
1328cb5caa98Sdjl 	/*
1329cb5caa98Sdjl 	 * use the generic nscd_initf for all database lookups
1330cb5caa98Sdjl 	 * (the TSD key is the pointer to the packed header)
1331cb5caa98Sdjl 	 */
1332cb5caa98Sdjl 	rc = set_initf_key(pbuf);
1333cb5caa98Sdjl 	if (rc != 0) {
1334cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL);
1335cb5caa98Sdjl 	}
1336cb5caa98Sdjl 	initf = nscd_initf;
1337cb5caa98Sdjl 
1338cb5caa98Sdjl 	/* Perform local search and pack results into return buffer */
1339cb5caa98Sdjl 	/* nscd's search ignores db_root */
1340cb5caa98Sdjl 	status = nss_search(NULL, initf, dbop, &arg);
1341cb5caa98Sdjl 
1342cb5caa98Sdjl 	/*
1343cb5caa98Sdjl 	 * If status is NSS_NOTFOUND and ldap also returned
1344cb5caa98Sdjl 	 * NSS_NOTFOUND, it is possible that the user does
1345cb5caa98Sdjl 	 * not have a credential, so check and see if
1346cb5caa98Sdjl 	 * needs to return NSS_ALTRETRY to let the main
1347cb5caa98Sdjl 	 * nscd get a chance to process the lookup
1348cb5caa98Sdjl 	 */
1349cb5caa98Sdjl 	if (swret.fallback == 1 && status == NSS_NOTFOUND) {
1350c70a8a3bSmichen 		OM_uint32	(*func)();
1351cb5caa98Sdjl 		OM_uint32	stat;
1352c70a8a3bSmichen 		nscd_rc_t	rc;
1353cb5caa98Sdjl 
1354c70a8a3bSmichen 		rc = get_gss_func((void **)&func);
1355c70a8a3bSmichen 		if (rc == NSCD_SUCCESS) {
1356c70a8a3bSmichen 			if (func(&stat, GSS_C_NO_CREDENTIAL,
1357cb5caa98Sdjl 			    NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) {
1358cb5caa98Sdjl 
1359cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1360cb5caa98Sdjl 				    NSCD_LOG_LEVEL_DEBUG)
1361cb5caa98Sdjl 			(me, "NSS_ALTRETRY: fallback to main nscd needed\n");
1362cb5caa98Sdjl 
1363cb5caa98Sdjl 				status = NSS_ALTRETRY;
1364cb5caa98Sdjl 			}
1365cb5caa98Sdjl 		}
1366c70a8a3bSmichen 	}
1367cb5caa98Sdjl 
1368cb5caa98Sdjl 	NSCD_SET_STATUS(pbuf, status, -1);
1369cb5caa98Sdjl 	errno = swret.errnum;
1370cb5caa98Sdjl 
1371cb5caa98Sdjl 	/*
1372d2ba247cSmichen 	 * Move result/status from args to packed buffer only if
1373d2ba247cSmichen 	 * arg was being used and rc from the switch engine is not
1374d2ba247cSmichen 	 * NSS_TRYLOCAL.
1375cb5caa98Sdjl 	 */
1376d2ba247cSmichen 	if (!swret.noarg && status != NSS_TRYLOCAL)
1377cb5caa98Sdjl 		nss_packed_set_status(buffer, length, status,  &arg);
1378cb5caa98Sdjl 
1379cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1380cb5caa98Sdjl 	(me, "switch engine result: source is %s, status %d, "
1381cb5caa98Sdjl 	"herrno is %d, errno is %s\n",
1382cb5caa98Sdjl 	    (swret.srci != -1) ? NSCD_NSW_SRC_NAME(swret.srci) : "<NOTSET>",
1383cb5caa98Sdjl 	    pbuf->p_status, pbuf->p_herrno, strerror(pbuf->p_errno));
1384cb5caa98Sdjl 
1385cb5caa98Sdjl 	/* clear the TSD key used by the generic initf */
1386cb5caa98Sdjl 	clear_initf_key();
1387cb5caa98Sdjl 	pbuf->nscdpriv = 0;
1388cb5caa98Sdjl }
1389cb5caa98Sdjl 
1390cb5caa98Sdjl static void
1391cb5caa98Sdjl nscd_map_contextp(void *buffer, nss_getent_t *contextp,
1392e37190e5Smichen 	nssuint_t **cookie_num_p, nssuint_t **seqnum_p, int setent)
1393cb5caa98Sdjl {
1394cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1395cb5caa98Sdjl 	nssuint_t		off;
1396cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1397cb5caa98Sdjl 	char			*me = "nscd_map_contextp";
1398e37190e5Smichen 	nscd_getent_p1_cookie_t	*cookie;
1399cb5caa98Sdjl 
1400cb5caa98Sdjl 	if (buffer == NULL) {
1401cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1402cb5caa98Sdjl 	}
1403cb5caa98Sdjl 
1404cb5caa98Sdjl 	off = pbuf->key_off;
1405e37190e5Smichen 	cookie = (nscd_getent_p1_cookie_t *)((void *)((char *)buffer + off));
1406cb5caa98Sdjl 	if (seqnum_p != NULL)
1407e37190e5Smichen 		*seqnum_p = &cookie->p1_seqnum;
1408cb5caa98Sdjl 
1409cb5caa98Sdjl 	/*
1410e37190e5Smichen 	 * if called by nss_psetent, and the passed in cookie number
1411e37190e5Smichen 	 * is NSCD_NEW_COOKIE, then there is no cookie yet, return a
1412e37190e5Smichen 	 * pointer pointing to where the cookie number will be stored.
1413e37190e5Smichen 	 * Also because there is no cookie to validate, just return
1414e37190e5Smichen 	 * success.
1415cb5caa98Sdjl 	 *
1416e37190e5Smichen 	 * On the other hand, if a cookie number is passed in, we need
1417e37190e5Smichen 	 * to validate the cookie number before returning.
1418cb5caa98Sdjl 	 */
1419e37190e5Smichen 	if (cookie_num_p != NULL)
1420e37190e5Smichen 		*cookie_num_p = &cookie->p1_cookie_num;
1421e37190e5Smichen 	if (setent == 1 && cookie->p1_cookie_num == NSCD_NEW_COOKIE) {
1422e37190e5Smichen 			NSCD_RETURN_STATUS_SUCCESS(pbuf);
1423e37190e5Smichen 	}
1424e37190e5Smichen 
1425e37190e5Smichen 	/*
1426e37190e5Smichen 	 * If the sequence number and start time match nscd's p0 cookie,
1427e37190e5Smichen 	 * then either setent was done twice in a row or this is the
1428e37190e5Smichen 	 * first getent after the setent, return success as well.
1429e37190e5Smichen 	 */
1430e37190e5Smichen 	if (cookie->p1_seqnum == NSCD_P0_COOKIE_SEQNUM) {
1431e37190e5Smichen 		nscd_getent_p0_cookie_t *p0c =
1432e37190e5Smichen 		    (nscd_getent_p0_cookie_t *)cookie;
1433e37190e5Smichen 		if (p0c->p0_time == _nscd_get_start_time())
1434cb5caa98Sdjl 			NSCD_RETURN_STATUS_SUCCESS(pbuf);
1435cb5caa98Sdjl 	}
1436cb5caa98Sdjl 
1437cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1438e37190e5Smichen 	(me, "cookie # = %lld,  sequence # = %lld\n",
1439e37190e5Smichen 	    cookie->p1_cookie_num, cookie->p1_seqnum);
1440cb5caa98Sdjl 
1441e37190e5Smichen 	ctx = _nscd_is_getent_ctx(cookie->p1_cookie_num);
1442cb5caa98Sdjl 
1443cb5caa98Sdjl 	if (ctx == NULL) {
1444cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1445e37190e5Smichen 		(me, "invalid cookie # (%lld)\n", cookie->p1_cookie_num);
1446cb5caa98Sdjl 
1447cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1448cb5caa98Sdjl 	}
1449cb5caa98Sdjl 
1450e37190e5Smichen 	/* if not called by nss_psetent, verify sequence number */
1451e37190e5Smichen 	if (setent != 1 && ctx->seq_num !=
1452e37190e5Smichen 	    (nscd_seq_num_t)cookie->p1_seqnum) {
1453cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1454e37190e5Smichen 		(me, "invalid sequence # (%lld)\n", cookie->p1_seqnum);
1455cb5caa98Sdjl 
1456cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1457cb5caa98Sdjl 	}
1458cb5caa98Sdjl 
1459cb5caa98Sdjl 	contextp->ctx = (struct nss_getent_context *)ctx;
1460cb5caa98Sdjl 
1461cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(pbuf);
1462cb5caa98Sdjl }
1463cb5caa98Sdjl 
1464cb5caa98Sdjl void
1465cb5caa98Sdjl nss_psetent(void *buffer, size_t length, pid_t pid)
1466cb5caa98Sdjl {
1467cb5caa98Sdjl 	nss_getent_t		context = { 0 };
1468cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1469e37190e5Smichen 	nssuint_t		*cookie_num_p;
1470e37190e5Smichen 	nssuint_t		*seqnum_p;
1471cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1472e37190e5Smichen 	nscd_getent_p0_cookie_t *p0c;
1473cb5caa98Sdjl 	char			*me = "nss_psetent";
1474cb5caa98Sdjl 
1475cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1476cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1477cb5caa98Sdjl 	}
1478cb5caa98Sdjl 
1479cb5caa98Sdjl 	/*
1480cb5caa98Sdjl 	 * If this is a per-user nscd, and the user does not have
1481cb5caa98Sdjl 	 * the necessary credential, return NSS_TRYLOCAL, so the
1482cb5caa98Sdjl 	 * setent/getent can be done locally in the process of the
1483cb5caa98Sdjl 	 * setent call
1484cb5caa98Sdjl 	 */
1485cb5caa98Sdjl 	if (_whoami == NSCD_CHILD) {
1486c70a8a3bSmichen 		OM_uint32	(*func)();
1487cb5caa98Sdjl 		OM_uint32	stat;
1488c70a8a3bSmichen 		nscd_rc_t	rc;
1489cb5caa98Sdjl 
1490c70a8a3bSmichen 		rc = get_gss_func((void **)&func);
1491c70a8a3bSmichen 		if (rc == NSCD_SUCCESS) {
1492c70a8a3bSmichen 			if (func(&stat, GSS_C_NO_CREDENTIAL,
1493cb5caa98Sdjl 			    NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) {
1494cb5caa98Sdjl 
1495cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE,
1496cb5caa98Sdjl 				    NSCD_LOG_LEVEL_DEBUG)
1497cb5caa98Sdjl 			(me, "NSS_TRYLOCAL: fallback to caller process\n");
1498cb5caa98Sdjl 				NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0);
1499cb5caa98Sdjl 			}
1500cb5caa98Sdjl 		}
1501c70a8a3bSmichen 	}
1502cb5caa98Sdjl 
1503e37190e5Smichen 	/* check cookie number */
1504e37190e5Smichen 	nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 1);
1505cb5caa98Sdjl 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1506cb5caa98Sdjl 		return;
1507e37190e5Smichen 
1508e37190e5Smichen 	/* set cookie number and sequence number */
1509e37190e5Smichen 	p0c = (nscd_getent_p0_cookie_t *)cookie_num_p;
1510e37190e5Smichen 	if (contextp->ctx ==  NULL) {
1511e37190e5Smichen 		/*
1512e37190e5Smichen 		 * first setent (no existing getent context),
1513e37190e5Smichen 		 * return a p0 cookie
1514e37190e5Smichen 		 */
1515e37190e5Smichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1516e37190e5Smichen 		(me, "first setent, no getent context yet\n");
1517e37190e5Smichen 	} else {
1518e37190e5Smichen 		/*
1519e37190e5Smichen 		 * doing setent on an existing getent context,
1520e37190e5Smichen 		 * release resources allocated and return a
1521e37190e5Smichen 		 * p0 cookie
1522e37190e5Smichen 		 */
1523e37190e5Smichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1524e37190e5Smichen 		(me, "setent resetting sequence number = %lld\n",  *seqnum_p);
1525e37190e5Smichen 
1526e37190e5Smichen 		_nscd_put_getent_ctx((nscd_getent_context_t *)contextp->ctx);
1527e37190e5Smichen 		contextp->ctx = NULL;
1528e37190e5Smichen 	}
1529e37190e5Smichen 
1530e37190e5Smichen 	p0c->p0_pid = pid;
1531e37190e5Smichen 	p0c->p0_time = _nscd_get_start_time();
1532e37190e5Smichen 	p0c->p0_seqnum = NSCD_P0_COOKIE_SEQNUM;
1533e37190e5Smichen 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1534e37190e5Smichen 	(me, "returning a p0 cookie: pid = %ld, time = %ld, seq #= %llx\n",
1535e37190e5Smichen 	    p0c->p0_pid, p0c->p0_time, p0c->p0_seqnum);
1536e37190e5Smichen 
1537e37190e5Smichen 	NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0);
1538e37190e5Smichen }
1539e37190e5Smichen 
1540e37190e5Smichen static void
1541e37190e5Smichen delayed_setent(nss_pheader_t *pbuf, nss_db_initf_t initf,
1542e37190e5Smichen 	nss_getent_t *contextp, nssuint_t *cookie_num_p,
1543e37190e5Smichen 	nssuint_t *seqnum_p, pid_t pid)
1544e37190e5Smichen {
1545e37190e5Smichen 	nscd_getent_context_t	*ctx;
1546e37190e5Smichen 	nscd_sw_return_t	swret = { 0 }, *swrp = &swret;
1547e37190e5Smichen 	char			*me = "delayed_setent";
1548e37190e5Smichen 
1549e37190e5Smichen 	/*
1550e37190e5Smichen 	 * check credential
1551e37190e5Smichen 	 */
1552e37190e5Smichen 	_nscd_APP_check_cred(pbuf, &pid, "NSCD_DELAYED_SETENT",
1553e37190e5Smichen 	    NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR);
1554e37190e5Smichen 	if (NSCD_STATUS_IS_NOT_OK(pbuf)) {
1555e37190e5Smichen 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1556e37190e5Smichen 		(me, "invalid credential\n");
1557e37190e5Smichen 		return;
1558e37190e5Smichen 	}
1559e37190e5Smichen 
1560cb5caa98Sdjl 	/*
1561cb5caa98Sdjl 	 * pass the packed header buffer pointer to nss_setent
1562cb5caa98Sdjl 	 */
1563cb5caa98Sdjl 	(void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp));
1564e37190e5Smichen 	swret.pbuf = pbuf;
1565cb5caa98Sdjl 
1566cb5caa98Sdjl 	/* Perform local setent and set context */
1567cb5caa98Sdjl 	nss_setent(NULL, initf, contextp);
1568cb5caa98Sdjl 
1569e37190e5Smichen 	/* insert cookie info into packed buffer header */
1570cb5caa98Sdjl 	ctx = (nscd_getent_context_t *)contextp->ctx;
1571cb5caa98Sdjl 	if (ctx != NULL) {
1572e37190e5Smichen 		*cookie_num_p = ctx->cookie_num;
1573e37190e5Smichen 		*seqnum_p = ctx->seq_num;
1574cb5caa98Sdjl 		ctx->pid = pid;
1575cb5caa98Sdjl 	} else {
1576cb5caa98Sdjl 		/*
1577cb5caa98Sdjl 		 * not able to allocate a getent context, the
1578cb5caa98Sdjl 		 * client should try the enumeration locally
1579cb5caa98Sdjl 		 */
1580e37190e5Smichen 		*cookie_num_p = NSCD_LOCAL_COOKIE;
1581e37190e5Smichen 		*seqnum_p = 0;
1582cb5caa98Sdjl 
1583cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1584e37190e5Smichen 		(me, "NSS_TRYLOCAL: cookie # = %lld,  sequence # = %lld\n",
1585e37190e5Smichen 		    *cookie_num_p, *seqnum_p);
1586cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0);
1587cb5caa98Sdjl 	}
1588e37190e5Smichen 
1589e37190e5Smichen 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1590e37190e5Smichen 	(me, "NSS_SUCCESS: cookie # = %lld,  sequence # = %lld\n",
1591e37190e5Smichen 	    ctx->cookie_num, ctx->seq_num);
1592e37190e5Smichen 
1593e37190e5Smichen 	NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0);
1594cb5caa98Sdjl }
1595cb5caa98Sdjl 
1596cb5caa98Sdjl void
1597cb5caa98Sdjl nss_pgetent(void *buffer, size_t length)
1598cb5caa98Sdjl {
1599cb5caa98Sdjl 	/* inputs */
1600cb5caa98Sdjl 	nss_db_initf_t		initf;
1601e37190e5Smichen 	nss_getent_t		context = { 0 };
1602cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1603e37190e5Smichen 	nss_XbyY_args_t		arg = { 0};
1604cb5caa98Sdjl 	nss_status_t		status;
1605e37190e5Smichen 	nssuint_t		*cookie_num_p;
1606e37190e5Smichen 	nssuint_t		*seqnum_p;
1607cb5caa98Sdjl 	nscd_getent_context_t	*ctx;
1608cb5caa98Sdjl 	int			rc;
1609cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1610cb5caa98Sdjl 	char			*me = "nss_pgetent";
1611cb5caa98Sdjl 
1612cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1613cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1614cb5caa98Sdjl 	}
1615cb5caa98Sdjl 
1616e37190e5Smichen 	/* verify the cookie passed in */
1617e37190e5Smichen 	nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 0);
1618e37190e5Smichen 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1619e37190e5Smichen 		return;
1620cb5caa98Sdjl 	/*
1621cb5caa98Sdjl 	 * use the generic nscd_initf for all the getent requests
1622cb5caa98Sdjl 	 * (the TSD key is the pointer to the packed header)
1623cb5caa98Sdjl 	 */
1624cb5caa98Sdjl 	rc = set_initf_key(pbuf);
1625cb5caa98Sdjl 	if (rc != 0) {
1626cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL);
1627cb5caa98Sdjl 	}
1628cb5caa98Sdjl 	initf = nscd_initf;
1629cb5caa98Sdjl 
1630e37190e5Smichen 	/* if no context yet, get one */
1631e37190e5Smichen 	if (contextp->ctx ==  NULL) {
1632e37190e5Smichen 		nscd_getent_p0_cookie_t *p0c =
1633e37190e5Smichen 		    (nscd_getent_p0_cookie_t *)cookie_num_p;
1634cb5caa98Sdjl 
1635e37190e5Smichen 		delayed_setent(pbuf, initf, contextp, cookie_num_p,
1636e37190e5Smichen 		    seqnum_p, p0c->p0_pid);
1637e37190e5Smichen 		if (NSCD_STATUS_IS_NOT_OK(pbuf)) {
1638e37190e5Smichen 			clear_initf_key();
1639cb5caa98Sdjl 			return;
1640e37190e5Smichen 		}
1641e37190e5Smichen 	}
1642e37190e5Smichen 
1643e37190e5Smichen 	status = nss_packed_context_init(buffer, length,
1644e37190e5Smichen 	    NULL, &initf, &contextp, &arg);
1645e37190e5Smichen 	if (status != NSS_SUCCESS) {
1646e37190e5Smichen 		NSCD_RETURN_STATUS(pbuf, status, -1);
1647e37190e5Smichen 	}
1648cb5caa98Sdjl 
1649cb5caa98Sdjl 	/* Perform local search and pack results into return buffer */
1650cb5caa98Sdjl 	status = nss_getent(NULL, initf, contextp, &arg);
1651cb5caa98Sdjl 	NSCD_SET_STATUS(pbuf, status, -1);
1652cb5caa98Sdjl 	nss_packed_set_status(buffer, length, status,  &arg);
1653cb5caa98Sdjl 
1654cb5caa98Sdjl 	/* increment sequence number in the buffer and nscd context */
1655cb5caa98Sdjl 	if (status == NSS_SUCCESS) {
1656cb5caa98Sdjl 		ctx = (nscd_getent_context_t *)contextp->ctx;
1657cb5caa98Sdjl 		ctx->seq_num++;
1658e37190e5Smichen 		*seqnum_p = ctx->seq_num;
1659e37190e5Smichen 		*cookie_num_p = ctx->cookie_num;
1660cb5caa98Sdjl 
1661cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1662e37190e5Smichen 		(me, "getent OK, new sequence # = %lld, len = %lld,"
1663e37190e5Smichen 		    " data = >>%s<<\n", *seqnum_p,
1664cb5caa98Sdjl 		    pbuf->data_len, (char *)buffer + pbuf->data_off);
1665cb5caa98Sdjl 	} else {
1666124771bbSmichen 		/* release the resources used */
1667cb5caa98Sdjl 		ctx = (nscd_getent_context_t *)contextp->ctx;
1668124771bbSmichen 		if (ctx != NULL) {
1669124771bbSmichen 			_nscd_put_getent_ctx(ctx);
1670124771bbSmichen 			contextp->ctx = NULL;
1671124771bbSmichen 		}
1672cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1673e37190e5Smichen 		(me, "getent failed, status = %d, sequence # = %lld\n",
1674e37190e5Smichen 		    status, *seqnum_p);
1675cb5caa98Sdjl 	}
1676cb5caa98Sdjl 
1677cb5caa98Sdjl 	/* clear the TSD key used by the generic initf */
1678cb5caa98Sdjl 	clear_initf_key();
1679cb5caa98Sdjl }
1680cb5caa98Sdjl 
1681cb5caa98Sdjl void
1682cb5caa98Sdjl nss_pendent(void *buffer, size_t length)
1683cb5caa98Sdjl {
1684e37190e5Smichen 	nss_getent_t		context = { 0 };
1685cb5caa98Sdjl 	nss_getent_t		*contextp = &context;
1686e37190e5Smichen 	nssuint_t		*seqnum_p;
1687e37190e5Smichen 	nssuint_t		*cookie_num_p;
1688cb5caa98Sdjl 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1689cb5caa98Sdjl 	char			*me = "nss_pendent";
1690cb5caa98Sdjl 
1691cb5caa98Sdjl 	if (buffer == NULL || length == 0) {
1692cb5caa98Sdjl 		NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT);
1693cb5caa98Sdjl 	}
1694cb5caa98Sdjl 
1695cb5caa98Sdjl 	/* map the contextp from the cookie information */
1696e37190e5Smichen 	nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 0);
1697cb5caa98Sdjl 	if (NSCD_STATUS_IS_NOT_OK(pbuf))
1698cb5caa98Sdjl 		return;
1699cb5caa98Sdjl 
1700e37190e5Smichen 	if (contextp->ctx == NULL)
1701e37190e5Smichen 		return;
1702e37190e5Smichen 
1703cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG)
1704e37190e5Smichen 	(me, "endent, cookie = %lld, sequence # = %lld\n",
1705e37190e5Smichen 	    *cookie_num_p, *seqnum_p);
1706cb5caa98Sdjl 
1707cb5caa98Sdjl 	/* Perform local endent and reset context */
1708cb5caa98Sdjl 	nss_endent(NULL, NULL, contextp);
1709cb5caa98Sdjl 	NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0);
1710cb5caa98Sdjl }
1711cb5caa98Sdjl 
1712cb5caa98Sdjl /*ARGSUSED*/
1713cb5caa98Sdjl void
1714cb5caa98Sdjl nss_pdelete(void *buffer, size_t length)
1715cb5caa98Sdjl {
1716cb5caa98Sdjl 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
1717cb5caa98Sdjl 
1718cb5caa98Sdjl 	/* unnecessary, kept for completeness */
1719cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(pbuf);
1720cb5caa98Sdjl }
1721