xref: /titanic_51/usr/src/cmd/nscd/nscd_frontend.c (revision b57459abfba36eb3068cfe44c6921168b4c4f774)
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  */
21cb5caa98Sdjl /*
22*b57459abSJulian Pullen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23cb5caa98Sdjl  * Use is subject to license terms.
24cb5caa98Sdjl  */
25cb5caa98Sdjl 
26cb5caa98Sdjl #include <stdlib.h>
27cb5caa98Sdjl #include <alloca.h>
28cb5caa98Sdjl #include <signal.h>
29cb5caa98Sdjl #include <sys/stat.h>
30cb5caa98Sdjl #include <unistd.h>
31cb5caa98Sdjl #include <pthread.h>
32cb5caa98Sdjl #include <time.h>
33cb5caa98Sdjl #include <errno.h>
34cb5caa98Sdjl #include <door.h>
35cb5caa98Sdjl #include <zone.h>
36cb5caa98Sdjl #include <resolv.h>
37cb5caa98Sdjl #include <sys/socket.h>
38cb5caa98Sdjl #include <net/route.h>
39cb5caa98Sdjl #include <string.h>
40cb5caa98Sdjl #include <net/if.h>
41cb5caa98Sdjl #include <sys/stat.h>
42cb5caa98Sdjl #include <fcntl.h>
43cb5caa98Sdjl #include "nscd_common.h"
44cb5caa98Sdjl #include "nscd_door.h"
45cb5caa98Sdjl #include "nscd_config.h"
46cb5caa98Sdjl #include "nscd_switch.h"
47cb5caa98Sdjl #include "nscd_log.h"
48cb5caa98Sdjl #include "nscd_selfcred.h"
49cb5caa98Sdjl #include "nscd_frontend.h"
50cb5caa98Sdjl #include "nscd_admin.h"
51cb5caa98Sdjl 
52cb5caa98Sdjl static void rts_mon(void);
53cb5caa98Sdjl static void keep_open_dns_socket(void);
54cb5caa98Sdjl 
55cb5caa98Sdjl extern nsc_ctx_t *cache_ctx_p[];
56cb5caa98Sdjl 
57cb5caa98Sdjl /*
58cb5caa98Sdjl  * Current active Configuration data for the frontend component
59cb5caa98Sdjl  */
60cb5caa98Sdjl static nscd_cfg_global_frontend_t	frontend_cfg_g;
61cb5caa98Sdjl static nscd_cfg_frontend_t		*frontend_cfg;
62cb5caa98Sdjl 
63cb5caa98Sdjl static int	max_servers = 0;
64cb5caa98Sdjl static int	max_servers_set = 0;
65cb5caa98Sdjl static int	per_user_is_on = 1;
66cb5caa98Sdjl 
67cb5caa98Sdjl static char	*main_execname;
68cb5caa98Sdjl static char	**main_argv;
69cb5caa98Sdjl extern int	_whoami;
70cb5caa98Sdjl extern long	activity;
71cb5caa98Sdjl extern mutex_t	activity_lock;
72cb5caa98Sdjl 
73cb5caa98Sdjl static sema_t	common_sema;
74cb5caa98Sdjl 
75cb5caa98Sdjl static thread_key_t	lookup_state_key;
76cb5caa98Sdjl static mutex_t		create_lock = DEFAULTMUTEX;
77cb5caa98Sdjl static int		num_servers = 0;
78cb5caa98Sdjl static thread_key_t	server_key;
79cb5caa98Sdjl 
80cb5caa98Sdjl /*
81cb5caa98Sdjl  * Bind a TSD value to a server thread. This enables the destructor to
82cb5caa98Sdjl  * be called if/when this thread exits.  This would be a programming
83cb5caa98Sdjl  * error, but better safe than sorry.
84cb5caa98Sdjl  */
85cb5caa98Sdjl /*ARGSUSED*/
86cb5caa98Sdjl static void *
87cb5caa98Sdjl server_tsd_bind(void *arg)
88cb5caa98Sdjl {
89cb5caa98Sdjl 	static void *value = 0;
90cb5caa98Sdjl 
91cb5caa98Sdjl 	/* disable cancellation to avoid hangs if server threads disappear */
92cb5caa98Sdjl 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
93cb5caa98Sdjl 	(void) thr_setspecific(server_key, value);
94cb5caa98Sdjl 	(void) door_return(NULL, 0, NULL, 0);
95cb5caa98Sdjl 
96cb5caa98Sdjl 	/* make lint happy */
97cb5caa98Sdjl 	return (NULL);
98cb5caa98Sdjl }
99cb5caa98Sdjl 
100cb5caa98Sdjl /*
101cb5caa98Sdjl  * Server threads are created here.
102cb5caa98Sdjl  */
103cb5caa98Sdjl /*ARGSUSED*/
104cb5caa98Sdjl static void
105cb5caa98Sdjl server_create(door_info_t *dip)
106cb5caa98Sdjl {
107cb5caa98Sdjl 	(void) mutex_lock(&create_lock);
108cb5caa98Sdjl 	if (++num_servers > max_servers) {
109cb5caa98Sdjl 		num_servers--;
110cb5caa98Sdjl 		(void) mutex_unlock(&create_lock);
111cb5caa98Sdjl 		return;
112cb5caa98Sdjl 	}
113cb5caa98Sdjl 	(void) mutex_unlock(&create_lock);
114cb5caa98Sdjl 	(void) thr_create(NULL, 0, server_tsd_bind, NULL,
115cb5caa98Sdjl 	    THR_BOUND|THR_DETACHED, NULL);
116cb5caa98Sdjl }
117cb5caa98Sdjl 
118cb5caa98Sdjl /*
119cb5caa98Sdjl  * Server thread are destroyed here
120cb5caa98Sdjl  */
121cb5caa98Sdjl /*ARGSUSED*/
122cb5caa98Sdjl static void
123cb5caa98Sdjl server_destroy(void *arg)
124cb5caa98Sdjl {
125cb5caa98Sdjl 	(void) mutex_lock(&create_lock);
126cb5caa98Sdjl 	num_servers--;
127cb5caa98Sdjl 	(void) mutex_unlock(&create_lock);
128cb5caa98Sdjl }
129cb5caa98Sdjl 
130cb5caa98Sdjl /*
131cb5caa98Sdjl  * get clearance
132cb5caa98Sdjl  */
133cb5caa98Sdjl int
134cb5caa98Sdjl _nscd_get_clearance(sema_t *sema) {
135cb5caa98Sdjl 	if (sema_trywait(&common_sema) == 0) {
136cb5caa98Sdjl 		(void) thr_setspecific(lookup_state_key, NULL);
137cb5caa98Sdjl 		return (0);
138cb5caa98Sdjl 	}
139cb5caa98Sdjl 
140cb5caa98Sdjl 	if (sema_trywait(sema) == 0) {
141cb5caa98Sdjl 		(void) thr_setspecific(lookup_state_key, (void*)1);
142cb5caa98Sdjl 		return (0);
143cb5caa98Sdjl 	}
144cb5caa98Sdjl 
145cb5caa98Sdjl 	return (1);
146cb5caa98Sdjl }
147cb5caa98Sdjl 
148cb5caa98Sdjl 
149cb5caa98Sdjl /*
150cb5caa98Sdjl  * release clearance
151cb5caa98Sdjl  */
152cb5caa98Sdjl int
153cb5caa98Sdjl _nscd_release_clearance(sema_t *sema) {
154cb5caa98Sdjl 	int	which;
155cb5caa98Sdjl 
156cb5caa98Sdjl 	(void) thr_getspecific(lookup_state_key, (void**)&which);
157cb5caa98Sdjl 	if (which == 0) /* from common pool */ {
158cb5caa98Sdjl 		(void) sema_post(&common_sema);
159cb5caa98Sdjl 		return (0);
160cb5caa98Sdjl 	}
161cb5caa98Sdjl 
162cb5caa98Sdjl 	(void) sema_post(sema);
163cb5caa98Sdjl 	return (1);
164cb5caa98Sdjl }
165cb5caa98Sdjl 
166cb5caa98Sdjl static void
167cb5caa98Sdjl dozip(void)
168cb5caa98Sdjl {
169cb5caa98Sdjl 	/* not much here */
170cb5caa98Sdjl }
171cb5caa98Sdjl 
172940a40eaSsm26363 /*
173940a40eaSsm26363  * _nscd_restart_if_cfgfile_changed()
174940a40eaSsm26363  * Restart if modification times of nsswitch.conf or resolv.conf have changed.
175940a40eaSsm26363  *
176940a40eaSsm26363  * If nsswitch.conf has changed then it is possible that sources for
177940a40eaSsm26363  * various backends have changed and therefore the current cached
178940a40eaSsm26363  * data may not be consistent with the new data sources.  By
179940a40eaSsm26363  * restarting the cache will be cleared and the new configuration will
180940a40eaSsm26363  * be used.
181940a40eaSsm26363  *
182940a40eaSsm26363  * The check for resolv.conf is made as only the first call to
183940a40eaSsm26363  * res_gethostbyname() or res_getaddrbyname() causes a call to
184940a40eaSsm26363  * res_ninit() to occur which in turn parses resolv.conf.  Therefore
185940a40eaSsm26363  * to benefit from changes to resolv.conf nscd must be restarted when
186940a40eaSsm26363  * resolv.conf is updated, removed or created.  If res_getXbyY calls
187940a40eaSsm26363  * are removed from NSS then this check could be removed.
188940a40eaSsm26363  *
189940a40eaSsm26363  */
19080b80bf0Smichen void
19180b80bf0Smichen _nscd_restart_if_cfgfile_changed()
192cb5caa98Sdjl {
193cb5caa98Sdjl 
194cb5caa98Sdjl 	static mutex_t		nsswitch_lock = DEFAULTMUTEX;
19580b80bf0Smichen 	static timestruc_t	last_nsswitch_check = { 0 };
19680b80bf0Smichen 	static timestruc_t	last_nsswitch_modified = { 0 };
197940a40eaSsm26363 	static timestruc_t	last_resolv_modified = { -1, 0 };
19886f95553Smichen 	static mutex_t		restarting_lock = DEFAULTMUTEX;
19986f95553Smichen 	static int 		restarting = 0;
20086f95553Smichen 	int			restart = 0;
201cb5caa98Sdjl 	time_t			now = time(NULL);
20280b80bf0Smichen 	char			*me = "_nscd_restart_if_cfgfile_changed";
203cb5caa98Sdjl 
204940a40eaSsm26363 #define	FLAG_RESTART_REQUIRED	if (restarting == 0) {\
205940a40eaSsm26363 					(void) mutex_lock(&restarting_lock);\
206940a40eaSsm26363 					if (restarting == 0) {\
207940a40eaSsm26363 						restarting = 1;\
208940a40eaSsm26363 						restart = 1;\
209940a40eaSsm26363 					}\
210940a40eaSsm26363 					(void) mutex_unlock(&restarting_lock);\
211940a40eaSsm26363 				}
212940a40eaSsm26363 
21386f95553Smichen 	if (restarting == 1)
21486f95553Smichen 		return;
21586f95553Smichen 
21680b80bf0Smichen 	if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME)
217cb5caa98Sdjl 		return;
218cb5caa98Sdjl 
219cb5caa98Sdjl 	(void) mutex_lock(&nsswitch_lock);
220cb5caa98Sdjl 
22180b80bf0Smichen 	if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) {
222cb5caa98Sdjl 		struct stat nss_buf;
223cb5caa98Sdjl 		struct stat res_buf;
224cb5caa98Sdjl 
22580b80bf0Smichen 		last_nsswitch_check.tv_sec = now;
22680b80bf0Smichen 		last_nsswitch_check.tv_nsec = 0;
227cb5caa98Sdjl 
228cb5caa98Sdjl 		(void) mutex_unlock(&nsswitch_lock); /* let others continue */
229cb5caa98Sdjl 
230cb5caa98Sdjl 		if (stat("/etc/nsswitch.conf", &nss_buf) < 0) {
23180b80bf0Smichen 			return;
23280b80bf0Smichen 		} else if (last_nsswitch_modified.tv_sec == 0) {
23380b80bf0Smichen 			last_nsswitch_modified = nss_buf.st_mtim;
23480b80bf0Smichen 		}
235cb5caa98Sdjl 
23680b80bf0Smichen 		if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec ||
23780b80bf0Smichen 		    (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec &&
238940a40eaSsm26363 		    last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) {
239940a40eaSsm26363 			FLAG_RESTART_REQUIRED;
24086f95553Smichen 		}
241940a40eaSsm26363 
242940a40eaSsm26363 		if (restart == 0) {
243940a40eaSsm26363 			if (stat("/etc/resolv.conf", &res_buf) < 0) {
244940a40eaSsm26363 				/* Unable to stat file, were we previously? */
245940a40eaSsm26363 				if (last_resolv_modified.tv_sec > 0) {
246940a40eaSsm26363 					/* Yes, it must have been removed. */
247940a40eaSsm26363 					FLAG_RESTART_REQUIRED;
248940a40eaSsm26363 				} else if (last_resolv_modified.tv_sec == -1) {
249940a40eaSsm26363 					/* No, then we've never seen it. */
250940a40eaSsm26363 					last_resolv_modified.tv_sec = 0;
251940a40eaSsm26363 				}
252940a40eaSsm26363 			} else if (last_resolv_modified.tv_sec == -1) {
253940a40eaSsm26363 				/* We've just started and file is present. */
254940a40eaSsm26363 				last_resolv_modified = res_buf.st_mtim;
255940a40eaSsm26363 			} else if (last_resolv_modified.tv_sec == 0) {
256940a40eaSsm26363 				/* Wasn't there at start-up. */
257940a40eaSsm26363 				FLAG_RESTART_REQUIRED;
258940a40eaSsm26363 			} else if (last_resolv_modified.tv_sec <
259940a40eaSsm26363 			    res_buf.st_mtim.tv_sec ||
260940a40eaSsm26363 			    (last_resolv_modified.tv_sec ==
261940a40eaSsm26363 			    res_buf.st_mtim.tv_sec &&
262940a40eaSsm26363 			    last_resolv_modified.tv_nsec <
263940a40eaSsm26363 			    res_buf.st_mtim.tv_nsec)) {
264940a40eaSsm26363 				FLAG_RESTART_REQUIRED;
26586f95553Smichen 			}
26686f95553Smichen 		}
26786f95553Smichen 
26886f95553Smichen 		if (restart == 1) {
269cb5caa98Sdjl 			char *fmri;
270cb5caa98Sdjl 
271cb5caa98Sdjl 			/*
272cb5caa98Sdjl 			 * if in self cred mode, kill the forker and
273cb5caa98Sdjl 			 * child nscds
274cb5caa98Sdjl 			 */
275cb5caa98Sdjl 			if (_nscd_is_self_cred_on(0, NULL)) {
276cb5caa98Sdjl 				_nscd_kill_forker();
277cb5caa98Sdjl 				_nscd_kill_all_children();
278cb5caa98Sdjl 			}
279cb5caa98Sdjl 
280cb5caa98Sdjl 			/*
281cb5caa98Sdjl 			 * time for restart
282cb5caa98Sdjl 			 */
283cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
284cb5caa98Sdjl 			(me, "nscd restart due to %s or %s change\n",
285cb5caa98Sdjl 			    "/etc/nsswitch.conf", "resolv.conf");
286cb5caa98Sdjl 			/*
287cb5caa98Sdjl 			 * try to restart under smf
288cb5caa98Sdjl 			 */
289cb5caa98Sdjl 			if ((fmri = getenv("SMF_FMRI")) == NULL) {
290cb5caa98Sdjl 				/* not running under smf - reexec */
291cb5caa98Sdjl 				(void) execv(main_execname, main_argv);
292cb5caa98Sdjl 				exit(1); /* just in case */
293cb5caa98Sdjl 			}
294cb5caa98Sdjl 
295cb5caa98Sdjl 			if (smf_restart_instance(fmri) == 0)
296cb5caa98Sdjl 				(void) sleep(10); /* wait a bit */
297cb5caa98Sdjl 			exit(1); /* give up waiting for resurrection */
298cb5caa98Sdjl 		}
299cb5caa98Sdjl 
300cb5caa98Sdjl 	} else
301cb5caa98Sdjl 		(void) mutex_unlock(&nsswitch_lock);
302cb5caa98Sdjl }
303cb5caa98Sdjl 
304cb5caa98Sdjl uid_t
305cb5caa98Sdjl _nscd_get_client_euid()
306cb5caa98Sdjl {
307cb5caa98Sdjl 	ucred_t	*uc = NULL;
308cb5caa98Sdjl 	uid_t	id;
309cb5caa98Sdjl 	char	*me = "get_client_euid";
310cb5caa98Sdjl 
311cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
312cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
313cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
314cb5caa98Sdjl 		return ((uid_t)-1);
315cb5caa98Sdjl 	}
316cb5caa98Sdjl 
317cb5caa98Sdjl 	id = ucred_geteuid(uc);
318cb5caa98Sdjl 	ucred_free(uc);
319cb5caa98Sdjl 	return (id);
320cb5caa98Sdjl }
321cb5caa98Sdjl 
322bf1e3beeSmichen /*
323*b57459abSJulian Pullen  * Check to see if the door client's euid is 0 or if it has required_priv
3246392794bSMichen Chang  * privilege. Return 0 if yes, -1 otherwise.
325*b57459abSJulian Pullen  * Supported values for required_priv are:
326*b57459abSJulian Pullen  *    - NSCD_ALL_PRIV: for all zones privileges
327*b57459abSJulian Pullen  *    - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
328bf1e3beeSmichen  */
329bf1e3beeSmichen int
330*b57459abSJulian Pullen _nscd_check_client_priv(int required_priv)
331bf1e3beeSmichen {
332bf1e3beeSmichen 	int			rc = 0;
333bf1e3beeSmichen 	ucred_t			*uc = NULL;
334bf1e3beeSmichen 	const priv_set_t	*eset;
335bf1e3beeSmichen 	char			*me = "_nscd_check_client_read_priv";
336*b57459abSJulian Pullen 	priv_set_t		*zs;	/* zone */
337bf1e3beeSmichen 
338bf1e3beeSmichen 	if (door_ucred(&uc) != 0) {
339bf1e3beeSmichen 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
340bf1e3beeSmichen 		(me, "door_ucred: %s\n", strerror(errno));
341bf1e3beeSmichen 		return (-1);
342bf1e3beeSmichen 	}
3436392794bSMichen Chang 
3446392794bSMichen Chang 	if (ucred_geteuid(uc) == 0) {
3456392794bSMichen Chang 		ucred_free(uc);
3466392794bSMichen Chang 		return (0);
3476392794bSMichen Chang 	}
3486392794bSMichen Chang 
349bf1e3beeSmichen 	eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
350*b57459abSJulian Pullen 	switch (required_priv) {
351*b57459abSJulian Pullen 		case NSCD_ALL_PRIV:
352*b57459abSJulian Pullen 			zs = priv_str_to_set("zone", ",", NULL);
353*b57459abSJulian Pullen 			if (!priv_isequalset(eset, zs)) {
354*b57459abSJulian Pullen 				_NSCD_LOG(NSCD_LOG_FRONT_END,
355*b57459abSJulian Pullen 				    NSCD_LOG_LEVEL_ERROR)
356*b57459abSJulian Pullen 				(me, "missing all zones privileges\n");
357*b57459abSJulian Pullen 				rc = -1;
358*b57459abSJulian Pullen 			}
359*b57459abSJulian Pullen 			priv_freeset(zs);
360*b57459abSJulian Pullen 			break;
361*b57459abSJulian Pullen 		case NSCD_READ_PRIV:
362bf1e3beeSmichen 			if (!priv_ismember(eset, PRIV_FILE_DAC_READ))
363bf1e3beeSmichen 				rc = -1;
364*b57459abSJulian Pullen 			break;
365*b57459abSJulian Pullen 		default:
366*b57459abSJulian Pullen 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
367*b57459abSJulian Pullen 			(me, "unknown required_priv: %d\n", required_priv);
368*b57459abSJulian Pullen 			rc = -1;
369*b57459abSJulian Pullen 			break;
370*b57459abSJulian Pullen 	}
371bf1e3beeSmichen 	ucred_free(uc);
372bf1e3beeSmichen 	return (rc);
373bf1e3beeSmichen }
374bf1e3beeSmichen 
375cb5caa98Sdjl static void
376cb5caa98Sdjl N2N_check_priv(
377cb5caa98Sdjl 	void			*buf,
378cb5caa98Sdjl 	char			*dc_str)
379cb5caa98Sdjl {
380cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)buf;
381cb5caa98Sdjl 	ucred_t			*uc = NULL;
382cb5caa98Sdjl 	const priv_set_t	*eset;
383cb5caa98Sdjl 	zoneid_t		zoneid;
384cb5caa98Sdjl 	int			errnum;
385cb5caa98Sdjl 	char			*me = "N2N_check_priv";
386cb5caa98Sdjl 
387cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
388cb5caa98Sdjl 		errnum = errno;
389cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
390cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
391cb5caa98Sdjl 
392cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
393cb5caa98Sdjl 	}
394cb5caa98Sdjl 
395cb5caa98Sdjl 	eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
396cb5caa98Sdjl 	zoneid = ucred_getzoneid(uc);
397cb5caa98Sdjl 
398cb5caa98Sdjl 	if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
399cb5caa98Sdjl 	    eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
400cb5caa98Sdjl 	    ucred_geteuid(uc) != 0) {
401cb5caa98Sdjl 
402cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
403cb5caa98Sdjl 		(me, "%s call failed(cred): caller pid %d, uid %d, "
404cb5caa98Sdjl 		    "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
405cb5caa98Sdjl 		    ucred_getruid(uc), ucred_geteuid(uc), zoneid);
406cb5caa98Sdjl 		ucred_free(uc);
407cb5caa98Sdjl 
408cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES);
409cb5caa98Sdjl 	}
410cb5caa98Sdjl 
411cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
412cb5caa98Sdjl 	(me, "nscd received %s cmd from pid %d, uid %d, "
413cb5caa98Sdjl 	    "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
414cb5caa98Sdjl 	    ucred_getruid(uc), ucred_geteuid(uc), zoneid);
415cb5caa98Sdjl 
416cb5caa98Sdjl 	ucred_free(uc);
417cb5caa98Sdjl 
418cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(phdr);
419cb5caa98Sdjl }
420cb5caa98Sdjl 
421e37190e5Smichen void
422e37190e5Smichen _nscd_APP_check_cred(
423cb5caa98Sdjl 	void		*buf,
424cb5caa98Sdjl 	pid_t		*pidp,
425e37190e5Smichen 	char		*dc_str,
426e37190e5Smichen 	int		log_comp,
427e37190e5Smichen 	int		log_level)
428cb5caa98Sdjl {
429cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
430cb5caa98Sdjl 	ucred_t		*uc = NULL;
431cb5caa98Sdjl 	uid_t		ruid;
432cb5caa98Sdjl 	uid_t		euid;
433e37190e5Smichen 	pid_t		pid;
434cb5caa98Sdjl 	int		errnum;
435e37190e5Smichen 	char		*me = "_nscd_APP_check_cred";
436cb5caa98Sdjl 
437cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
438cb5caa98Sdjl 		errnum = errno;
439e37190e5Smichen 		_NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
440cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
441cb5caa98Sdjl 
442cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
443cb5caa98Sdjl 	}
444cb5caa98Sdjl 
445e37190e5Smichen 	NSCD_SET_STATUS_SUCCESS(phdr);
446e37190e5Smichen 	pid = ucred_getpid(uc);
447cb5caa98Sdjl 	if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
448cb5caa98Sdjl 	    euid = ucred_geteuid(uc))) {
449e37190e5Smichen 		if (pidp != NULL) {
450e37190e5Smichen 			if (*pidp == (pid_t)-1)
451e37190e5Smichen 				*pidp = pid;
452e37190e5Smichen 			else if (*pidp != pid) {
453e37190e5Smichen 				NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
454e37190e5Smichen 			}
455e37190e5Smichen 		}
456e37190e5Smichen 	} else {
457e37190e5Smichen 		NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
458cb5caa98Sdjl 	}
459cb5caa98Sdjl 
460cb5caa98Sdjl 	ucred_free(uc);
461cb5caa98Sdjl 
462e37190e5Smichen 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
463e37190e5Smichen 		_NSCD_LOG(log_comp, log_level)
464e37190e5Smichen 		(me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
465e37190e5Smichen 		    "euid %d, header ruid %d, header euid %d\n", dc_str,
466e37190e5Smichen 		    pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
467e37190e5Smichen 		    ((nss_pheader_t *)(buf))->p_ruid,
468e37190e5Smichen 		    ((nss_pheader_t *)(buf))->p_euid);
469e37190e5Smichen 	}
470cb5caa98Sdjl }
471cb5caa98Sdjl 
472606f6aa3Smichen /* log error and return -1 when an invalid packed buffer header is found */
473606f6aa3Smichen static int
474606f6aa3Smichen pheader_error(nss_pheader_t *phdr, uint32_t call_number)
475606f6aa3Smichen {
476606f6aa3Smichen 	char *call_num_str;
477606f6aa3Smichen 
478606f6aa3Smichen 	switch (call_number) {
479606f6aa3Smichen 	case NSCD_SEARCH:
480606f6aa3Smichen 		call_num_str = "NSCD_SEARCH";
481606f6aa3Smichen 		break;
482606f6aa3Smichen 	case NSCD_SETENT:
483606f6aa3Smichen 		call_num_str = "NSCD_SETENT";
484606f6aa3Smichen 		break;
485606f6aa3Smichen 	case NSCD_GETENT:
486606f6aa3Smichen 		call_num_str = "NSCD_GETENT";
487606f6aa3Smichen 		break;
488606f6aa3Smichen 	case NSCD_ENDENT:
489606f6aa3Smichen 		call_num_str = "NSCD_ENDENT";
490606f6aa3Smichen 		break;
491606f6aa3Smichen 	case NSCD_PUT:
492606f6aa3Smichen 		call_num_str = "NSCD_PUT";
493606f6aa3Smichen 		break;
494606f6aa3Smichen 	case NSCD_GETHINTS:
495606f6aa3Smichen 		call_num_str = "NSCD_GETHINTS";
496606f6aa3Smichen 		break;
497606f6aa3Smichen 	default:
498606f6aa3Smichen 		call_num_str = "UNKNOWN";
499606f6aa3Smichen 		break;
500606f6aa3Smichen 	}
501606f6aa3Smichen 
502606f6aa3Smichen 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
503606f6aa3Smichen 	("pheader_error", "call number %s: invalid packed buffer header\n",
504606f6aa3Smichen 	    call_num_str);
505606f6aa3Smichen 
506606f6aa3Smichen 	NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
507606f6aa3Smichen 	return (-1);
508606f6aa3Smichen }
509606f6aa3Smichen 
510606f6aa3Smichen /*
511606f6aa3Smichen  * Validate the header of a getXbyY or setent/getent/endent request.
512606f6aa3Smichen  * Return 0 if good, -1 otherwise.
513606f6aa3Smichen  *
514606f6aa3Smichen  * A valid header looks like the following (size is arg_size, does
515606f6aa3Smichen  * not include the output area):
516606f6aa3Smichen  * +----------------------------------+ --
517606f6aa3Smichen  * | nss_pheader_t (header fixed part)| ^
518606f6aa3Smichen  * |                                  | |
519606f6aa3Smichen  * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
520606f6aa3Smichen  * | data_off ....                    | |
521606f6aa3Smichen  * |                                  | v
522606f6aa3Smichen  * +----------------------------------+ <----- dbd_off
523606f6aa3Smichen  * | dbd (database description)       | ^
524606f6aa3Smichen  * | nss_dbd_t + up to 3 strings      | |
525606f6aa3Smichen  * | length = sizeof(nss_dbd_t) +     | len = key_off - dbd_off
526606f6aa3Smichen  * |          length of 3 strings +   | |
527606f6aa3Smichen  * |          length of padding       | |
528606f6aa3Smichen  * | (total length in multiple of 4)  | v
529606f6aa3Smichen  * +----------------------------------+ <----- key_off
530606f6aa3Smichen  * | lookup key                       | ^
531606f6aa3Smichen  * | nss_XbyY_key_t, content varies,  | |
532606f6aa3Smichen  * | based on database and lookup op  | len = data_off - key_off
533606f6aa3Smichen  * | length = data_off - key_off      | |
534606f6aa3Smichen  * | including padding, multiple of 4 | v
535606f6aa3Smichen  * +----------------------------------+ <----- data_off (= arg_size)
536606f6aa3Smichen  * |                                  | ^
537606f6aa3Smichen  * | area to hold results             | |
538606f6aa3Smichen  * |                                  | len = data_len (= pbufsiz -
539606f6aa3Smichen  * |                                  | |                 data_off)
540606f6aa3Smichen  * |                                  | v
541606f6aa3Smichen  * +----------------------------------+ <----- pbufsiz
542606f6aa3Smichen  */
543606f6aa3Smichen static int
544606f6aa3Smichen validate_pheader(
545606f6aa3Smichen 	void		*argp,
546606f6aa3Smichen 	size_t		arg_size,
547606f6aa3Smichen 	uint32_t	call_number)
548606f6aa3Smichen {
549606f6aa3Smichen 	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
550606f6aa3Smichen 	nssuint_t	l1, l2;
551606f6aa3Smichen 
552606f6aa3Smichen 	/*
553606f6aa3Smichen 	 * current version is NSCD_HEADER_REV, length of the fixed part
554606f6aa3Smichen 	 * of the header must match the size of nss_pheader_t
555606f6aa3Smichen 	 */
556606f6aa3Smichen 	if (phdr->p_version != NSCD_HEADER_REV ||
557606f6aa3Smichen 	    phdr->dbd_off != sizeof (nss_pheader_t))
558606f6aa3Smichen 		return (pheader_error(phdr, call_number));
559606f6aa3Smichen 
560606f6aa3Smichen 	/*
561606f6aa3Smichen 	 * buffer size and offsets must be in multiple of 4
562606f6aa3Smichen 	 */
563606f6aa3Smichen 	if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
564606f6aa3Smichen 	    (phdr->data_off & 3))
565606f6aa3Smichen 		return (pheader_error(phdr, call_number));
566606f6aa3Smichen 
567606f6aa3Smichen 	/*
568606f6aa3Smichen 	 * the input arg_size is the length of the request header
569606f6aa3Smichen 	 * and should be less than NSCD_PHDR_MAXLEN
570606f6aa3Smichen 	 */
571606f6aa3Smichen 	if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
572606f6aa3Smichen 		return (pheader_error(phdr, call_number));
573606f6aa3Smichen 
574606f6aa3Smichen 	/* get length of the dbd area */
575606f6aa3Smichen 	l1 = phdr->key_off - phdr-> dbd_off;
576606f6aa3Smichen 
577606f6aa3Smichen 	/*
578606f6aa3Smichen 	 * dbd area may contain padding, so length of dbd should
579606f6aa3Smichen 	 * not be less than the length of the actual data
580606f6aa3Smichen 	 */
581606f6aa3Smichen 	if (l1 < phdr->dbd_len)
582606f6aa3Smichen 		return (pheader_error(phdr, call_number));
583606f6aa3Smichen 
584606f6aa3Smichen 	/* get length of the key area */
585606f6aa3Smichen 	l2 = phdr->data_off - phdr->key_off;
586606f6aa3Smichen 
587606f6aa3Smichen 	/*
588606f6aa3Smichen 	 * key area may contain padding, so length of key area should
589606f6aa3Smichen 	 * not be less than the length of the actual data
590606f6aa3Smichen 	 */
591606f6aa3Smichen 	if (l2 < phdr->key_len)
592606f6aa3Smichen 		return (pheader_error(phdr, call_number));
593606f6aa3Smichen 
594606f6aa3Smichen 	/*
595606f6aa3Smichen 	 * length of fixed part + lengths of dbd and key area = length of
596606f6aa3Smichen 	 * the request header
597606f6aa3Smichen 	 */
598606f6aa3Smichen 	if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
599606f6aa3Smichen 		return (pheader_error(phdr, call_number));
600606f6aa3Smichen 
601606f6aa3Smichen 	/* header length + data length = buffer length */
602606f6aa3Smichen 	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
603606f6aa3Smichen 		return (pheader_error(phdr, call_number));
604606f6aa3Smichen 
605606f6aa3Smichen 	return (0);
606606f6aa3Smichen }
607606f6aa3Smichen 
608606f6aa3Smichen /* log error and return -1 when an invalid nscd to nscd buffer is found */
609606f6aa3Smichen static int
610606f6aa3Smichen N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
611606f6aa3Smichen {
612606f6aa3Smichen 	char *call_num_str;
613606f6aa3Smichen 
614606f6aa3Smichen 	switch (call_number) {
615606f6aa3Smichen 	case NSCD_PING:
616606f6aa3Smichen 		call_num_str = "NSCD_PING";
617606f6aa3Smichen 		break;
618606f6aa3Smichen 
619606f6aa3Smichen 	case NSCD_IMHERE:
620606f6aa3Smichen 		call_num_str = "NSCD_IMHERE";
621606f6aa3Smichen 		break;
622606f6aa3Smichen 
623606f6aa3Smichen 	case NSCD_PULSE:
624606f6aa3Smichen 		call_num_str = "NSCD_PULSE";
625606f6aa3Smichen 		break;
626606f6aa3Smichen 
627606f6aa3Smichen 	case NSCD_FORK:
628606f6aa3Smichen 		call_num_str = "NSCD_FORK";
629606f6aa3Smichen 		break;
630606f6aa3Smichen 
631606f6aa3Smichen 	case NSCD_KILL:
632606f6aa3Smichen 		call_num_str = "NSCD_KILL";
633606f6aa3Smichen 		break;
634606f6aa3Smichen 
635606f6aa3Smichen 	case NSCD_REFRESH:
636606f6aa3Smichen 		call_num_str = "NSCD_REFRESH";
637606f6aa3Smichen 		break;
638606f6aa3Smichen 
639606f6aa3Smichen 	case NSCD_GETPUADMIN:
640606f6aa3Smichen 		call_num_str = "NSCD_GETPUADMIN";
641606f6aa3Smichen 		break;
642606f6aa3Smichen 
643606f6aa3Smichen 	case NSCD_GETADMIN:
644606f6aa3Smichen 		call_num_str = "NSCD_GETADMIN";
645606f6aa3Smichen 		break;
646606f6aa3Smichen 
647606f6aa3Smichen 	case NSCD_SETADMIN:
648606f6aa3Smichen 		call_num_str = "NSCD_SETADMIN";
649606f6aa3Smichen 		break;
650606f6aa3Smichen 
651606f6aa3Smichen 	case NSCD_KILLSERVER:
652606f6aa3Smichen 		call_num_str = "NSCD_KILLSERVER";
653606f6aa3Smichen 		break;
654606f6aa3Smichen 	default:
655606f6aa3Smichen 		call_num_str = "UNKNOWN";
656606f6aa3Smichen 		break;
657606f6aa3Smichen 	}
658606f6aa3Smichen 
659606f6aa3Smichen 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
660bf1e3beeSmichen 	("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str);
661606f6aa3Smichen 
662606f6aa3Smichen 	NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
663606f6aa3Smichen 	    NSCD_DOOR_BUFFER_CHECK_FAILED);
664606f6aa3Smichen 
665606f6aa3Smichen 	return (-1);
666606f6aa3Smichen }
667606f6aa3Smichen 
668606f6aa3Smichen /*
669606f6aa3Smichen  * Validate the buffer of an nscd to nscd request.
670606f6aa3Smichen  * Return 0 if good, -1 otherwise.
671606f6aa3Smichen  *
672606f6aa3Smichen  * A valid buffer looks like the following (size is arg_size):
673606f6aa3Smichen  * +----------------------------------+ --
674606f6aa3Smichen  * | nss_pheader_t (header fixed part)| ^
675606f6aa3Smichen  * |                                  | |
676606f6aa3Smichen  * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
677606f6aa3Smichen  * | data_off ....                    | |
678606f6aa3Smichen  * |                                  | v
679606f6aa3Smichen  * +----------------------------------+ <---dbd_off = key_off = data_off
680606f6aa3Smichen  * |                                  | ^
681606f6aa3Smichen  * | input data/output data           | |
682606f6aa3Smichen  * | OR no data                       | len = data_len (= pbufsiz -
683606f6aa3Smichen  * |                                  | |                 data_off)
684606f6aa3Smichen  * |                                  | | len could be zero
685606f6aa3Smichen  * |                                  | v
686606f6aa3Smichen  * +----------------------------------+ <--- pbufsiz
687606f6aa3Smichen  */
688606f6aa3Smichen static int
689606f6aa3Smichen validate_N2Nbuf(
690606f6aa3Smichen 	void		*argp,
691606f6aa3Smichen 	size_t		arg_size,
692606f6aa3Smichen 	uint32_t	call_number)
693606f6aa3Smichen {
694606f6aa3Smichen 	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
695606f6aa3Smichen 
696606f6aa3Smichen 	/*
697606f6aa3Smichen 	 * current version is NSCD_HEADER_REV, length of the fixed part
698606f6aa3Smichen 	 * of the header must match the size of nss_pheader_t
699606f6aa3Smichen 	 */
700606f6aa3Smichen 	if (phdr->p_version != NSCD_HEADER_REV ||
701606f6aa3Smichen 	    phdr->dbd_off != sizeof (nss_pheader_t))
702606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
703606f6aa3Smichen 
704606f6aa3Smichen 	/*
705606f6aa3Smichen 	 * There are no dbd and key data, so the dbd, key, data
706606f6aa3Smichen 	 * offsets should be equal
707606f6aa3Smichen 	 */
708606f6aa3Smichen 	if (phdr->dbd_off != phdr->key_off ||
709606f6aa3Smichen 	    phdr->dbd_off != phdr->data_off)
710606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
711606f6aa3Smichen 
712606f6aa3Smichen 	/*
713606f6aa3Smichen 	 * the input arg_size is the buffer length and should
714606f6aa3Smichen 	 * be less or equal than NSCD_N2NBUF_MAXLEN
715606f6aa3Smichen 	 */
716606f6aa3Smichen 	if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
717606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
718606f6aa3Smichen 
719606f6aa3Smichen 	/* header length + data length = buffer length */
720606f6aa3Smichen 	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
721606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
722606f6aa3Smichen 
723606f6aa3Smichen 	return (0);
724606f6aa3Smichen }
725606f6aa3Smichen 
726cb5caa98Sdjl static void
727cb5caa98Sdjl lookup(char *argp, size_t arg_size)
728cb5caa98Sdjl {
729cb5caa98Sdjl 	nsc_lookup_args_t	largs;
730cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
731cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
732cb5caa98Sdjl 
733cb5caa98Sdjl 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
734cb5caa98Sdjl 	    sizeof (space));
735cb5caa98Sdjl 
736606f6aa3Smichen 	/*
737606f6aa3Smichen 	 * make sure the first couple bytes of the data area is null,
738606f6aa3Smichen 	 * so that bad strings in the packed header stop here
739606f6aa3Smichen 	 */
740606f6aa3Smichen 	(void) memset((char *)phdr + phdr->data_off, 0, 16);
741606f6aa3Smichen 
742cb5caa98Sdjl 	(void) memset(&largs, 0, sizeof (largs));
743cb5caa98Sdjl 	largs.buffer = argp;
744cb5caa98Sdjl 	largs.bufsize = arg_size;
745cb5caa98Sdjl 	nsc_lookup(&largs, 0);
746cb5caa98Sdjl 
747cb5caa98Sdjl 	/*
748cb5caa98Sdjl 	 * only the PUN needs to keep track of the
749cb5caa98Sdjl 	 * activity count to determine when to
750cb5caa98Sdjl 	 * terminate itself
751cb5caa98Sdjl 	 */
752cb5caa98Sdjl 	if (_whoami == NSCD_CHILD) {
753cb5caa98Sdjl 		(void) mutex_lock(&activity_lock);
754cb5caa98Sdjl 		++activity;
755cb5caa98Sdjl 		(void) mutex_unlock(&activity_lock);
756cb5caa98Sdjl 	}
757cb5caa98Sdjl 
758cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
759cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
760cb5caa98Sdjl }
761cb5caa98Sdjl 
762cb5caa98Sdjl static void
763cb5caa98Sdjl getent(char *argp, size_t arg_size)
764cb5caa98Sdjl {
765cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
766cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
767cb5caa98Sdjl 
768bf1e3beeSmichen 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space));
769cb5caa98Sdjl 
770cb5caa98Sdjl 	nss_pgetent(argp, arg_size);
771cb5caa98Sdjl 
772cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
773cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
774cb5caa98Sdjl }
775cb5caa98Sdjl 
776cb5caa98Sdjl static int
777cb5caa98Sdjl is_db_per_user(void *buf, char *dblist)
778cb5caa98Sdjl {
779cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
780cb5caa98Sdjl 	nss_dbd_t	*pdbd;
781cb5caa98Sdjl 	char		*dbname, *dbn;
782cb5caa98Sdjl 	int		len;
783cb5caa98Sdjl 
784cb5caa98Sdjl 	/* copy db name into a temp buffer */
785cb5caa98Sdjl 	pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
786cb5caa98Sdjl 	dbname = (char *)pdbd + pdbd->o_name;
787cb5caa98Sdjl 	len = strlen(dbname);
788cb5caa98Sdjl 	dbn = alloca(len + 2);
789cb5caa98Sdjl 	(void) memcpy(dbn, dbname, len);
790cb5caa98Sdjl 
791cb5caa98Sdjl 	/* check if <dbname> + ',' can be found in the dblist string */
792cb5caa98Sdjl 	dbn[len] = ',';
793cb5caa98Sdjl 	dbn[len + 1] = '\0';
794cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
795cb5caa98Sdjl 		return (1);
796cb5caa98Sdjl 
797cb5caa98Sdjl 	/*
798cb5caa98Sdjl 	 * check if <dbname> can be found in the last part
799cb5caa98Sdjl 	 * of the dblist string
800cb5caa98Sdjl 	 */
801cb5caa98Sdjl 	dbn[len] = '\0';
802cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
803cb5caa98Sdjl 		return (1);
804cb5caa98Sdjl 
805cb5caa98Sdjl 	return (0);
806cb5caa98Sdjl }
807cb5caa98Sdjl 
808cb5caa98Sdjl /*
809cb5caa98Sdjl  * Check to see if all conditions are met for processing per-user
810cb5caa98Sdjl  * requests. Returns 1 if yes, -1 if backend is not configured,
811cb5caa98Sdjl  * 0 otherwise.
812cb5caa98Sdjl  */
813cb5caa98Sdjl static int
814cb5caa98Sdjl need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
815cb5caa98Sdjl {
816cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
817cb5caa98Sdjl 
818cb5caa98Sdjl 	NSCD_SET_STATUS_SUCCESS(phdr);
819cb5caa98Sdjl 
820cb5caa98Sdjl 	/* if already a per-user nscd, no need to get per-user door */
821cb5caa98Sdjl 	if (whoami == NSCD_CHILD)
822cb5caa98Sdjl 		return (0);
823cb5caa98Sdjl 
824cb5caa98Sdjl 	/* forker shouldn't be asked */
825cb5caa98Sdjl 	if (whoami == NSCD_FORKER) {
826cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
827cb5caa98Sdjl 		return (0);
828cb5caa98Sdjl 	}
829cb5caa98Sdjl 
830cb5caa98Sdjl 	/* if door client is root, no need for a per-user door */
831cb5caa98Sdjl 	if (uid == 0)
832cb5caa98Sdjl 		return (0);
833cb5caa98Sdjl 
834cb5caa98Sdjl 	/*
835cb5caa98Sdjl 	 * if per-user lookup is not configured, no per-user
836cb5caa98Sdjl 	 * door available
837cb5caa98Sdjl 	 */
838cb5caa98Sdjl 	if (_nscd_is_self_cred_on(0, dblist) == 0)
839cb5caa98Sdjl 		return (-1);
840cb5caa98Sdjl 
841cb5caa98Sdjl 	/*
842cb5caa98Sdjl 	 * if per-user lookup is not configured for the db,
843cb5caa98Sdjl 	 * don't bother
844cb5caa98Sdjl 	 */
845cb5caa98Sdjl 	if (is_db_per_user(phdr, *dblist) == 0)
846cb5caa98Sdjl 		return (0);
847cb5caa98Sdjl 
848cb5caa98Sdjl 	return (1);
849cb5caa98Sdjl }
850cb5caa98Sdjl 
851cb5caa98Sdjl static void
852cb5caa98Sdjl if_selfcred_return_per_user_door(char *argp, size_t arg_size,
853cb5caa98Sdjl 	door_desc_t *dp, int whoami)
854cb5caa98Sdjl {
855cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)((void *)argp);
856cb5caa98Sdjl 	char		*dblist;
857cb5caa98Sdjl 	int		door = -1;
858cb5caa98Sdjl 	int		rc = 0;
859cb5caa98Sdjl 	door_desc_t	desc;
860606f6aa3Smichen 	char		*space;
861606f6aa3Smichen 	int		len;
862cb5caa98Sdjl 
863cb5caa98Sdjl 	/*
864cb5caa98Sdjl 	 * check to see if self-cred is configured and
865cb5caa98Sdjl 	 * need to return an alternate PUN door
866cb5caa98Sdjl 	 */
867cb5caa98Sdjl 	if (per_user_is_on == 1) {
868cb5caa98Sdjl 		rc = need_per_user_door(argp, whoami,
869cb5caa98Sdjl 		    _nscd_get_client_euid(), &dblist);
870cb5caa98Sdjl 		if (rc == -1)
871cb5caa98Sdjl 			per_user_is_on = 0;
872cb5caa98Sdjl 	}
873cb5caa98Sdjl 	if (rc <= 0) {
874cb5caa98Sdjl 		/*
875cb5caa98Sdjl 		 * self-cred not configured, and no error detected,
876cb5caa98Sdjl 		 * return to continue the door call processing
877cb5caa98Sdjl 		 */
878cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
879cb5caa98Sdjl 			return;
880cb5caa98Sdjl 		else
881cb5caa98Sdjl 			/*
882cb5caa98Sdjl 			 * configured but error detected,
883cb5caa98Sdjl 			 * stop the door call processing
884cb5caa98Sdjl 			 */
885cb5caa98Sdjl 			(void) door_return(argp, phdr->data_off, NULL, 0);
886cb5caa98Sdjl 	}
887cb5caa98Sdjl 
888cb5caa98Sdjl 	/* get the alternate PUN door */
889cb5caa98Sdjl 	_nscd_proc_alt_get(argp, &door);
890cb5caa98Sdjl 	if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
891cb5caa98Sdjl 		(void) door_return(argp, phdr->data_off, NULL, 0);
892cb5caa98Sdjl 	}
893cb5caa98Sdjl 
894cb5caa98Sdjl 	/* return the alternate door descriptor */
895606f6aa3Smichen 	len = strlen(dblist) + 1;
896606f6aa3Smichen 	space = alloca(arg_size + len);
897606f6aa3Smichen 	phdr->data_len = len;
898606f6aa3Smichen 	(void) memcpy(space, phdr, arg_size);
899606f6aa3Smichen 	(void) strncpy((char *)space + arg_size, dblist, len);
900cb5caa98Sdjl 	dp = &desc;
901cb5caa98Sdjl 	dp->d_attributes = DOOR_DESCRIPTOR;
902cb5caa98Sdjl 	dp->d_data.d_desc.d_descriptor = door;
903606f6aa3Smichen 	arg_size += len;
904606f6aa3Smichen 	(void) door_return(space, arg_size, dp, 1);
905cb5caa98Sdjl }
906cb5caa98Sdjl 
907cb5caa98Sdjl /*ARGSUSED*/
908cb5caa98Sdjl static void
909cb5caa98Sdjl switcher(void *cookie, char *argp, size_t arg_size,
910cb5caa98Sdjl     door_desc_t *dp, uint_t n_desc)
911cb5caa98Sdjl {
912cb5caa98Sdjl 	int			iam;
913cb5caa98Sdjl 	pid_t			ent_pid = -1;
914cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)((void *)argp);
915cb5caa98Sdjl 	void			*uptr;
916606f6aa3Smichen 	int			len;
917606f6aa3Smichen 	size_t			buflen;
918cb5caa98Sdjl 	int			callnum;
919cb5caa98Sdjl 	char			*me = "switcher";
920cb5caa98Sdjl 
921cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
922cb5caa98Sdjl 	(me, "switcher ...\n");
923cb5caa98Sdjl 
924cb5caa98Sdjl 	if (argp == DOOR_UNREF_DATA) {
925cb5caa98Sdjl 		(void) printf("Door Slam... exiting\n");
926cb5caa98Sdjl 		exit(0);
927cb5caa98Sdjl 	}
928cb5caa98Sdjl 
929cb5caa98Sdjl 	if (argp == NULL) { /* empty door call */
930cb5caa98Sdjl 		(void) door_return(NULL, 0, 0, 0); /* return the favor */
931cb5caa98Sdjl 	}
932cb5caa98Sdjl 
933cb5caa98Sdjl 	/*
934cb5caa98Sdjl 	 *  need to restart if main nscd and config file(s) changed
935cb5caa98Sdjl 	 */
936cb5caa98Sdjl 	if (_whoami == NSCD_MAIN)
93780b80bf0Smichen 		_nscd_restart_if_cfgfile_changed();
938cb5caa98Sdjl 
939cb5caa98Sdjl 	if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
940606f6aa3Smichen 
941606f6aa3Smichen 		/* make sure the packed buffer header is good */
942606f6aa3Smichen 		if (validate_pheader(argp, arg_size,
943606f6aa3Smichen 		    phdr->nsc_callnumber) == -1)
944606f6aa3Smichen 			(void) door_return(argp, arg_size, NULL, 0);
945606f6aa3Smichen 
946cb5caa98Sdjl 		switch (phdr->nsc_callnumber) {
947606f6aa3Smichen 
948cb5caa98Sdjl 		case NSCD_SEARCH:
949cb5caa98Sdjl 
950cb5caa98Sdjl 		/* if a fallback to main nscd, skip per-user setup */
951cb5caa98Sdjl 		if (phdr->p_status != NSS_ALTRETRY)
952cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
953cb5caa98Sdjl 			    dp, _whoami);
954cb5caa98Sdjl 		lookup(argp, arg_size);
955cb5caa98Sdjl 
956cb5caa98Sdjl 		break;
957cb5caa98Sdjl 
958cb5caa98Sdjl 		case NSCD_SETENT:
959cb5caa98Sdjl 
960e37190e5Smichen 		_nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
961e37190e5Smichen 		    NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
962cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
963cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
964cb5caa98Sdjl 			    dp, _whoami);
965cb5caa98Sdjl 			nss_psetent(argp, arg_size, ent_pid);
966cb5caa98Sdjl 		}
967cb5caa98Sdjl 		break;
968cb5caa98Sdjl 
969cb5caa98Sdjl 		case NSCD_GETENT:
970cb5caa98Sdjl 
971cb5caa98Sdjl 		getent(argp, arg_size);
972cb5caa98Sdjl 		break;
973cb5caa98Sdjl 
974cb5caa98Sdjl 		case NSCD_ENDENT:
975cb5caa98Sdjl 
976cb5caa98Sdjl 		nss_pendent(argp, arg_size);
977cb5caa98Sdjl 		break;
978cb5caa98Sdjl 
979cb5caa98Sdjl 		case NSCD_PUT:
980cb5caa98Sdjl 
981cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
982cb5caa98Sdjl 		(me, "door call NSCD_PUT not supported yet\n");
983cb5caa98Sdjl 
984cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
985cb5caa98Sdjl 		break;
986cb5caa98Sdjl 
987cb5caa98Sdjl 		case NSCD_GETHINTS:
988cb5caa98Sdjl 
989cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
990cb5caa98Sdjl 		(me, "door call NSCD_GETHINTS not supported yet\n");
991cb5caa98Sdjl 
992cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
993cb5caa98Sdjl 		break;
994cb5caa98Sdjl 
995cb5caa98Sdjl 		default:
996cb5caa98Sdjl 
997cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
998cb5caa98Sdjl 		(me, "Unknown name service door call op %x\n",
999cb5caa98Sdjl 		    phdr->nsc_callnumber);
1000cb5caa98Sdjl 
1001cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1002cb5caa98Sdjl 		break;
1003cb5caa98Sdjl 		}
1004cb5caa98Sdjl 
1005cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
1006cb5caa98Sdjl 	}
1007cb5caa98Sdjl 
1008cb5caa98Sdjl 	iam = NSCD_MAIN;
1009cb5caa98Sdjl 	callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
1010cb5caa98Sdjl 	if (callnum == NSCD_IMHERE ||
1011cb5caa98Sdjl 	    callnum == NSCD_PULSE || callnum == NSCD_FORK)
1012cb5caa98Sdjl 		iam = phdr->nsc_callnumber & NSCD_WHOAMI;
1013cb5caa98Sdjl 	else
1014cb5caa98Sdjl 		callnum = phdr->nsc_callnumber;
1015cb5caa98Sdjl 
1016cb5caa98Sdjl 	/* nscd -> nscd v2 calls */
1017606f6aa3Smichen 
1018606f6aa3Smichen 	/* make sure the buffer is good */
1019606f6aa3Smichen 	if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
1020606f6aa3Smichen 		(void) door_return(argp, arg_size, NULL, 0);
1021606f6aa3Smichen 
1022cb5caa98Sdjl 	switch (callnum) {
1023cb5caa98Sdjl 
1024cb5caa98Sdjl 	case NSCD_PING:
1025cb5caa98Sdjl 		NSCD_SET_STATUS_SUCCESS(phdr);
1026cb5caa98Sdjl 		break;
1027cb5caa98Sdjl 
1028cb5caa98Sdjl 	case NSCD_IMHERE:
1029cb5caa98Sdjl 		_nscd_proc_iamhere(argp, dp, n_desc, iam);
1030cb5caa98Sdjl 		break;
1031cb5caa98Sdjl 
1032cb5caa98Sdjl 	case NSCD_PULSE:
1033cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_PULSE");
1034cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
1035cb5caa98Sdjl 			_nscd_proc_pulse(argp, iam);
1036cb5caa98Sdjl 		break;
1037cb5caa98Sdjl 
1038cb5caa98Sdjl 	case NSCD_FORK:
1039cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_FORK");
1040cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
1041cb5caa98Sdjl 			_nscd_proc_fork(argp, iam);
1042cb5caa98Sdjl 		break;
1043cb5caa98Sdjl 
1044cb5caa98Sdjl 	case NSCD_KILL:
1045cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILL");
1046cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
1047cb5caa98Sdjl 			exit(0);
1048cb5caa98Sdjl 		break;
1049cb5caa98Sdjl 
1050cb5caa98Sdjl 	case NSCD_REFRESH:
1051606f6aa3Smichen 		N2N_check_priv(argp, "NSCD_REFRESH");
1052606f6aa3Smichen 		if (NSCD_STATUS_IS_OK(phdr)) {
1053cb5caa98Sdjl 			if (_nscd_refresh() != NSCD_SUCCESS)
1054cb5caa98Sdjl 				exit(1);
1055cb5caa98Sdjl 			NSCD_SET_STATUS_SUCCESS(phdr);
1056606f6aa3Smichen 		}
1057cb5caa98Sdjl 		break;
1058cb5caa98Sdjl 
1059cb5caa98Sdjl 	case NSCD_GETPUADMIN:
1060cb5caa98Sdjl 
1061cb5caa98Sdjl 		if (_nscd_is_self_cred_on(0, NULL)) {
1062cb5caa98Sdjl 			_nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
1063cb5caa98Sdjl 		} else {
1064cb5caa98Sdjl 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1065cb5caa98Sdjl 			    NSCD_SELF_CRED_NOT_CONFIGURED);
1066cb5caa98Sdjl 		}
1067cb5caa98Sdjl 		break;
1068cb5caa98Sdjl 
1069cb5caa98Sdjl 	case NSCD_GETADMIN:
1070cb5caa98Sdjl 
1071cb5caa98Sdjl 		len = _nscd_door_getadmin((void *)argp);
1072cb5caa98Sdjl 		if (len == 0)
1073cb5caa98Sdjl 			break;
1074cb5caa98Sdjl 
1075cb5caa98Sdjl 		/* size of door buffer not big enough, allocate one */
1076cb5caa98Sdjl 		NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
1077cb5caa98Sdjl 
1078cb5caa98Sdjl 		/* copy packed header */
1079cb5caa98Sdjl 		*(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
1080cb5caa98Sdjl 
1081cb5caa98Sdjl 		/* set new buffer size */
1082cb5caa98Sdjl 		((nss_pheader_t *)uptr)->pbufsiz = buflen;
1083cb5caa98Sdjl 
1084cb5caa98Sdjl 		/* try one more time */
1085cb5caa98Sdjl 		(void) _nscd_door_getadmin((void *)uptr);
1086cb5caa98Sdjl 		(void) door_return(uptr, buflen, NULL, 0);
1087cb5caa98Sdjl 		break;
1088cb5caa98Sdjl 
1089cb5caa98Sdjl 	case NSCD_SETADMIN:
1090cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_SETADMIN");
1091cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
1092cb5caa98Sdjl 			_nscd_door_setadmin(argp);
1093cb5caa98Sdjl 		break;
1094cb5caa98Sdjl 
1095cb5caa98Sdjl 	case NSCD_KILLSERVER:
1096cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILLSERVER");
1097cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
1098cb5caa98Sdjl 			/* also kill the forker nscd if one is running */
1099cb5caa98Sdjl 			_nscd_kill_forker();
1100cb5caa98Sdjl 			exit(0);
1101cb5caa98Sdjl 		}
1102cb5caa98Sdjl 		break;
1103cb5caa98Sdjl 
1104cb5caa98Sdjl 	default:
1105cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1106cb5caa98Sdjl 		(me, "Unknown name service door call op %d\n",
1107cb5caa98Sdjl 		    phdr->nsc_callnumber);
1108cb5caa98Sdjl 
1109cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1110cb5caa98Sdjl 
1111cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
1112cb5caa98Sdjl 		break;
1113cb5caa98Sdjl 
1114cb5caa98Sdjl 	}
1115cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
1116cb5caa98Sdjl }
1117cb5caa98Sdjl 
1118cb5caa98Sdjl int
1119cb5caa98Sdjl _nscd_setup_server(char *execname, char **argv)
1120cb5caa98Sdjl {
1121cb5caa98Sdjl 
1122cb5caa98Sdjl 	int		fd;
1123cb5caa98Sdjl 	int		errnum;
1124cb5caa98Sdjl 	int		bind_failed = 0;
112580b80bf0Smichen 	mode_t		old_mask;
1126cb5caa98Sdjl 	struct stat	buf;
1127cb5caa98Sdjl 	sigset_t	myset;
1128cb5caa98Sdjl 	struct sigaction action;
1129cb5caa98Sdjl 	char		*me = "_nscd_setup_server";
1130cb5caa98Sdjl 
1131cb5caa98Sdjl 	main_execname = execname;
1132cb5caa98Sdjl 	main_argv = argv;
1133cb5caa98Sdjl 
113482714199Ssdussud 	/* Any nscd process is to ignore SIGPIPE */
113582714199Ssdussud 	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
113682714199Ssdussud 		errnum = errno;
113782714199Ssdussud 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
113882714199Ssdussud 		(me, "signal (SIGPIPE): %s\n", strerror(errnum));
113982714199Ssdussud 		return (-1);
114082714199Ssdussud 	}
114182714199Ssdussud 
1142cb5caa98Sdjl 	keep_open_dns_socket();
1143cb5caa98Sdjl 
1144cb5caa98Sdjl 	/*
1145cb5caa98Sdjl 	 * the max number of server threads should be fixed now, so
1146cb5caa98Sdjl 	 * set flag to indicate that no in-flight change is allowed
1147cb5caa98Sdjl 	 */
1148cb5caa98Sdjl 	max_servers_set = 1;
1149cb5caa98Sdjl 
1150cb5caa98Sdjl 	(void) thr_keycreate(&lookup_state_key, NULL);
1151bf1e3beeSmichen 	(void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads,
1152cb5caa98Sdjl 	    USYNC_THREAD, 0);
1153cb5caa98Sdjl 
1154cb5caa98Sdjl 	/* Establish server thread pool */
1155cb5caa98Sdjl 	(void) door_server_create(server_create);
1156cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
1157cb5caa98Sdjl 		errnum = errno;
1158cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1159cb5caa98Sdjl 		(me, "thr_keycreate (server thread): %s\n",
1160cb5caa98Sdjl 		    strerror(errnum));
1161cb5caa98Sdjl 		return (-1);
1162cb5caa98Sdjl 	}
1163cb5caa98Sdjl 
1164cb5caa98Sdjl 	/* Create a door */
1165cb5caa98Sdjl 	if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1166cb5caa98Sdjl 	    DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
1167cb5caa98Sdjl 		errnum = errno;
1168cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1169cb5caa98Sdjl 		(me, "door_create: %s\n", strerror(errnum));
1170cb5caa98Sdjl 		return (-1);
1171cb5caa98Sdjl 	}
1172cb5caa98Sdjl 
1173cb5caa98Sdjl 	/* if not main nscd, no more setup to do */
1174cb5caa98Sdjl 	if (_whoami != NSCD_MAIN)
1175cb5caa98Sdjl 		return (fd);
1176cb5caa98Sdjl 
1177cb5caa98Sdjl 	/* bind to file system */
1178bf1e3beeSmichen 	if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) {
1179cb5caa98Sdjl 		if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
1180cb5caa98Sdjl 			int	newfd;
118180b80bf0Smichen 
118280b80bf0Smichen 			/* make sure the door will be readable by all */
118380b80bf0Smichen 			old_mask = umask(0);
1184cb5caa98Sdjl 			if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
1185cb5caa98Sdjl 				errnum = errno;
1186cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1187cb5caa98Sdjl 				    NSCD_LOG_LEVEL_ERROR)
1188cb5caa98Sdjl 				(me, "Cannot create %s: %s\n",
1189cb5caa98Sdjl 				    TSOL_NAME_SERVICE_DOOR,
1190cb5caa98Sdjl 				    strerror(errnum));
1191cb5caa98Sdjl 				bind_failed = 1;
1192cb5caa98Sdjl 			}
119380b80bf0Smichen 			/* rstore the old file mode creation mask */
119480b80bf0Smichen 			(void) umask(old_mask);
1195cb5caa98Sdjl 			(void) close(newfd);
1196cb5caa98Sdjl 		}
1197cb5caa98Sdjl 		if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
1198cb5caa98Sdjl 			if (errno != EEXIST) {
1199cb5caa98Sdjl 				errnum = errno;
1200cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1201cb5caa98Sdjl 				    NSCD_LOG_LEVEL_ERROR)
1202cb5caa98Sdjl 				(me, "Cannot symlink %s: %s\n",
1203bf1e3beeSmichen 				    NAME_SERVICE_DOOR, strerror(errnum));
1204cb5caa98Sdjl 				bind_failed = 1;
1205cb5caa98Sdjl 			}
1206cb5caa98Sdjl 		}
1207cb5caa98Sdjl 	} else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
1208cb5caa98Sdjl 		int	newfd;
120980b80bf0Smichen 
121080b80bf0Smichen 		/* make sure the door will be readable by all */
121180b80bf0Smichen 		old_mask = umask(0);
1212cb5caa98Sdjl 		if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
1213cb5caa98Sdjl 			errnum = errno;
1214cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1215cb5caa98Sdjl 			(me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
1216cb5caa98Sdjl 			    strerror(errnum));
1217cb5caa98Sdjl 			bind_failed = 1;
1218cb5caa98Sdjl 		}
121980b80bf0Smichen 		/* rstore the old file mode creation mask */
122080b80bf0Smichen 		(void) umask(old_mask);
1221cb5caa98Sdjl 		(void) close(newfd);
1222cb5caa98Sdjl 	}
1223cb5caa98Sdjl 
1224cb5caa98Sdjl 	if (bind_failed == 1) {
1225cb5caa98Sdjl 		(void) door_revoke(fd);
1226cb5caa98Sdjl 		return (-1);
1227cb5caa98Sdjl 	}
1228cb5caa98Sdjl 
1229cb5caa98Sdjl 	if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
1230cb5caa98Sdjl 		if ((errno != EBUSY) ||
1231cb5caa98Sdjl 		    (fdetach(NAME_SERVICE_DOOR) <  0) ||
1232cb5caa98Sdjl 		    (fattach(fd, NAME_SERVICE_DOOR) < 0)) {
1233cb5caa98Sdjl 			errnum = errno;
1234bf1e3beeSmichen 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1235cb5caa98Sdjl 			(me, "fattach: %s\n", strerror(errnum));
1236cb5caa98Sdjl 			(void) door_revoke(fd);
1237cb5caa98Sdjl 			return (-1);
1238cb5caa98Sdjl 		}
1239cb5caa98Sdjl 	}
1240cb5caa98Sdjl 
1241cb5caa98Sdjl 	/*
1242cb5caa98Sdjl 	 * kick off routing socket monitor thread
1243cb5caa98Sdjl 	 */
1244cb5caa98Sdjl 	if (thr_create(NULL, NULL,
1245cb5caa98Sdjl 	    (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1246cb5caa98Sdjl 		errnum = errno;
1247cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1248cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
1249cb5caa98Sdjl 		    strerror(errnum));
1250cb5caa98Sdjl 
1251cb5caa98Sdjl 		(void) door_revoke(fd);
1252cb5caa98Sdjl 		return (-1);
1253cb5caa98Sdjl 	}
1254cb5caa98Sdjl 
1255cb5caa98Sdjl 	/*
1256cb5caa98Sdjl 	 * set up signal handler for SIGHUP
1257cb5caa98Sdjl 	 */
1258cb5caa98Sdjl 	action.sa_handler = dozip;
1259cb5caa98Sdjl 	action.sa_flags = 0;
1260cb5caa98Sdjl 	(void) sigemptyset(&action.sa_mask);
1261cb5caa98Sdjl 	(void) sigemptyset(&myset);
1262cb5caa98Sdjl 	(void) sigaddset(&myset, SIGHUP);
1263cb5caa98Sdjl 
1264cb5caa98Sdjl 	if (sigaction(SIGHUP, &action, NULL) < 0) {
1265cb5caa98Sdjl 		errnum = errno;
1266cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1267cb5caa98Sdjl 		(me, "sigaction (SIGHUP): %s\n", strerror(errnum));
1268cb5caa98Sdjl 
1269cb5caa98Sdjl 		(void) door_revoke(fd);
1270cb5caa98Sdjl 		return (-1);
1271cb5caa98Sdjl 	}
1272cb5caa98Sdjl 
1273cb5caa98Sdjl 	return (fd);
1274cb5caa98Sdjl }
1275cb5caa98Sdjl 
1276cb5caa98Sdjl int
1277cb5caa98Sdjl _nscd_setup_child_server(int did)
1278cb5caa98Sdjl {
1279cb5caa98Sdjl 
1280cb5caa98Sdjl 	int		errnum;
1281cb5caa98Sdjl 	int		fd;
1282cb5caa98Sdjl 	nscd_rc_t	rc;
1283cb5caa98Sdjl 	char		*me = "_nscd_setup_child_server";
1284cb5caa98Sdjl 
1285cb5caa98Sdjl 	/* Re-establish our own server thread pool */
1286cb5caa98Sdjl 	(void) door_server_create(server_create);
1287cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
1288cb5caa98Sdjl 		errnum = errno;
1289cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1290cb5caa98Sdjl 		(me, "thr_keycreate failed: %s", strerror(errnum));
1291cb5caa98Sdjl 		return (-1);
1292cb5caa98Sdjl 	}
1293cb5caa98Sdjl 
1294cb5caa98Sdjl 	/*
1295cb5caa98Sdjl 	 * Create a new door.
1296cb5caa98Sdjl 	 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1297cb5caa98Sdjl 	 */
1298cb5caa98Sdjl 	(void) close(did);
1299bf1e3beeSmichen 	if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1300cb5caa98Sdjl 	    DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
1301cb5caa98Sdjl 		errnum = errno;
1302cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1303cb5caa98Sdjl 		(me, "door_create failed: %s", strerror(errnum));
1304cb5caa98Sdjl 		return (-1);
1305cb5caa98Sdjl 	}
1306cb5caa98Sdjl 
1307cb5caa98Sdjl 	/*
1308cb5caa98Sdjl 	 * kick off routing socket monitor thread
1309cb5caa98Sdjl 	 */
1310cb5caa98Sdjl 	if (thr_create(NULL, NULL,
1311cb5caa98Sdjl 	    (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1312cb5caa98Sdjl 		errnum = errno;
1313cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1314cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
1315cb5caa98Sdjl 		    strerror(errnum));
1316cb5caa98Sdjl 		(void) door_revoke(fd);
1317cb5caa98Sdjl 		return (-1);
1318cb5caa98Sdjl 	}
1319cb5caa98Sdjl 
1320cb5caa98Sdjl 	/*
1321cb5caa98Sdjl 	 * start monitoring the states of the name service clients
1322cb5caa98Sdjl 	 */
1323cb5caa98Sdjl 	rc = _nscd_init_smf_monitor();
1324cb5caa98Sdjl 	if (rc != NSCD_SUCCESS) {
1325cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1326cb5caa98Sdjl 	(me, "unable to start the SMF monitor (rc = %d)\n", rc);
1327cb5caa98Sdjl 
1328cb5caa98Sdjl 		(void) door_revoke(fd);
1329cb5caa98Sdjl 		return (-1);
1330cb5caa98Sdjl 	}
1331cb5caa98Sdjl 
1332cb5caa98Sdjl 	return (fd);
1333cb5caa98Sdjl }
1334cb5caa98Sdjl 
1335cb5caa98Sdjl nscd_rc_t
1336cb5caa98Sdjl _nscd_alloc_frontend_cfg()
1337cb5caa98Sdjl {
1338cb5caa98Sdjl 	frontend_cfg  = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
1339cb5caa98Sdjl 	if (frontend_cfg == NULL)
1340cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
1341cb5caa98Sdjl 
1342cb5caa98Sdjl 	return (NSCD_SUCCESS);
1343cb5caa98Sdjl }
1344cb5caa98Sdjl 
1345cb5caa98Sdjl 
1346cb5caa98Sdjl /* ARGSUSED */
1347cb5caa98Sdjl nscd_rc_t
1348cb5caa98Sdjl _nscd_cfg_frontend_notify(
1349cb5caa98Sdjl 	void				*data,
1350cb5caa98Sdjl 	struct nscd_cfg_param_desc	*pdesc,
1351cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1352cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
1353cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
1354cb5caa98Sdjl 	void				*cookie)
1355cb5caa98Sdjl {
1356cb5caa98Sdjl 	void				*dp;
1357cb5caa98Sdjl 
1358cb5caa98Sdjl 	/*
1359cb5caa98Sdjl 	 * At init time, the whole group of config params are received.
1360cb5caa98Sdjl 	 * At update time, group or individual parameter value could
1361cb5caa98Sdjl 	 * be received.
1362cb5caa98Sdjl 	 */
1363cb5caa98Sdjl 
1364cb5caa98Sdjl 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
1365cb5caa98Sdjl 	    _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1366cb5caa98Sdjl 		/*
1367cb5caa98Sdjl 		 * group data is received, copy in the
1368cb5caa98Sdjl 		 * entire strcture
1369cb5caa98Sdjl 		 */
1370bf1e3beeSmichen 		if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1371bf1e3beeSmichen 			frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data;
1372cb5caa98Sdjl 		else
1373cb5caa98Sdjl 			frontend_cfg[nswdb->index] =
1374cb5caa98Sdjl 			    *(nscd_cfg_frontend_t *)data;
1375cb5caa98Sdjl 
1376cb5caa98Sdjl 	} else {
1377cb5caa98Sdjl 		/*
1378cb5caa98Sdjl 		 * individual paramater is received: copy in the
1379cb5caa98Sdjl 		 * parameter value.
1380cb5caa98Sdjl 		 */
1381bf1e3beeSmichen 		if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1382cb5caa98Sdjl 			dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1383cb5caa98Sdjl 		else
1384cb5caa98Sdjl 			dp = (char *)&frontend_cfg[nswdb->index] +
1385cb5caa98Sdjl 			    pdesc->p_offset;
1386cb5caa98Sdjl 		(void) memcpy(dp, data, pdesc->p_size);
1387cb5caa98Sdjl 	}
1388cb5caa98Sdjl 
1389cb5caa98Sdjl 	return (NSCD_SUCCESS);
1390cb5caa98Sdjl }
1391cb5caa98Sdjl 
1392cb5caa98Sdjl /* ARGSUSED */
1393cb5caa98Sdjl nscd_rc_t
1394cb5caa98Sdjl _nscd_cfg_frontend_verify(
1395cb5caa98Sdjl 	void				*data,
1396cb5caa98Sdjl 	struct	nscd_cfg_param_desc	*pdesc,
1397cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1398cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
1399cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
1400cb5caa98Sdjl 	void				**cookie)
1401cb5caa98Sdjl {
1402cb5caa98Sdjl 
1403cb5caa98Sdjl 	char				*me = "_nscd_cfg_frontend_verify";
1404cb5caa98Sdjl 
1405cb5caa98Sdjl 	/*
1406cb5caa98Sdjl 	 * if max. number of server threads is set and in effect,
1407cb5caa98Sdjl 	 * don't allow changing of the frontend configuration
1408cb5caa98Sdjl 	 */
1409cb5caa98Sdjl 	if (max_servers_set) {
1410cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1411cb5caa98Sdjl 	(me, "changing of the frontend configuration not allowed now");
1412cb5caa98Sdjl 
1413cb5caa98Sdjl 		return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1414cb5caa98Sdjl 	}
1415cb5caa98Sdjl 
1416cb5caa98Sdjl 	return (NSCD_SUCCESS);
1417cb5caa98Sdjl }
1418cb5caa98Sdjl 
1419cb5caa98Sdjl /* ARGSUSED */
1420cb5caa98Sdjl nscd_rc_t
1421cb5caa98Sdjl _nscd_cfg_frontend_get_stat(
1422cb5caa98Sdjl 	void				**stat,
1423cb5caa98Sdjl 	struct nscd_cfg_stat_desc	*sdesc,
1424cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1425cb5caa98Sdjl 	nscd_cfg_flag_t			*dflag,
1426cb5caa98Sdjl 	void				(**free_stat)(void *stat),
1427cb5caa98Sdjl 	nscd_cfg_error_t		**errorp)
1428cb5caa98Sdjl {
1429cb5caa98Sdjl 	return (NSCD_SUCCESS);
1430cb5caa98Sdjl }
1431cb5caa98Sdjl 
1432cb5caa98Sdjl void
1433cb5caa98Sdjl _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1434cb5caa98Sdjl {
1435cb5caa98Sdjl 	int	i, j;
1436cb5caa98Sdjl 	char	*dbn;
1437cb5caa98Sdjl 
1438cb5caa98Sdjl 	if (max_servers == 0)
1439cb5caa98Sdjl 		max_servers = frontend_cfg_g.common_worker_threads +
1440cb5caa98Sdjl 		    frontend_cfg_g.cache_hit_threads;
1441cb5caa98Sdjl 
1442cb5caa98Sdjl 	for (i = 0; i < NSCD_NUM_DB; i++) {
1443cb5caa98Sdjl 
1444cb5caa98Sdjl 		dbn = NSCD_NSW_DB_NAME(i);
1445cb5caa98Sdjl 		if (strcasecmp(dbn, cache_name) == 0) {
1446cb5caa98Sdjl 			j = frontend_cfg[i].worker_thread_per_nsw_db;
1447cb5caa98Sdjl 			(void) sema_init(sema, j, USYNC_THREAD, 0);
1448cb5caa98Sdjl 			max_servers += j;
1449cb5caa98Sdjl 			break;
1450cb5caa98Sdjl 		}
1451cb5caa98Sdjl 	}
1452cb5caa98Sdjl }
1453cb5caa98Sdjl 
1454cb5caa98Sdjl /*
1455cb5caa98Sdjl  * Monitor the routing socket.  Address lists stored in the ipnodes
1456cb5caa98Sdjl  * cache are sorted based on destination address selection rules,
1457cb5caa98Sdjl  * so when things change that could affect that sorting (interfaces
1458cb5caa98Sdjl  * go up or down, flags change, etc.), we clear that cache so the
1459cb5caa98Sdjl  * list will be re-ordered the next time the hostname is resolved.
1460cb5caa98Sdjl  */
1461cb5caa98Sdjl static void
1462cb5caa98Sdjl rts_mon(void)
1463cb5caa98Sdjl {
1464cb5caa98Sdjl 	int	rt_sock, rdlen, idx;
1465cb5caa98Sdjl 	union {
1466cb5caa98Sdjl 		struct {
1467cb5caa98Sdjl 			struct rt_msghdr rtm;
1468cb5caa98Sdjl 			struct sockaddr_storage addrs[RTA_NUMBITS];
1469cb5caa98Sdjl 		} r;
1470cb5caa98Sdjl 		struct if_msghdr ifm;
1471cb5caa98Sdjl 		struct ifa_msghdr ifam;
1472cb5caa98Sdjl 	} mbuf;
1473cb5caa98Sdjl 	struct ifa_msghdr *ifam = &mbuf.ifam;
1474cb5caa98Sdjl 	char	*me = "rts_mon";
1475cb5caa98Sdjl 
1476cb5caa98Sdjl 	rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1477cb5caa98Sdjl 	if (rt_sock < 0) {
1478cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1479cb5caa98Sdjl 		(me, "Failed to open routing socket: %s\n", strerror(errno));
1480cb5caa98Sdjl 		thr_exit(0);
1481cb5caa98Sdjl 	}
1482cb5caa98Sdjl 
1483cb5caa98Sdjl 	for (;;) {
1484cb5caa98Sdjl 		rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1485cb5caa98Sdjl 		if (rdlen <= 0) {
1486cb5caa98Sdjl 			if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1487cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1488cb5caa98Sdjl 				    NSCD_LOG_LEVEL_ERROR)
1489cb5caa98Sdjl 				(me, "routing socket read: %s\n",
1490cb5caa98Sdjl 				    strerror(errno));
1491cb5caa98Sdjl 				thr_exit(0);
1492cb5caa98Sdjl 			}
1493cb5caa98Sdjl 			continue;
1494cb5caa98Sdjl 		}
1495cb5caa98Sdjl 		if (ifam->ifam_version != RTM_VERSION) {
1496cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1497cb5caa98Sdjl 				    NSCD_LOG_LEVEL_ERROR)
1498cb5caa98Sdjl 				(me, "rx unknown version (%d) on "
1499cb5caa98Sdjl 				    "routing socket.\n",
1500cb5caa98Sdjl 				    ifam->ifam_version);
1501cb5caa98Sdjl 			continue;
1502cb5caa98Sdjl 		}
1503cb5caa98Sdjl 		switch (ifam->ifam_type) {
1504cb5caa98Sdjl 		case RTM_NEWADDR:
1505cb5caa98Sdjl 		case RTM_DELADDR:
1506cb5caa98Sdjl 			/* if no ipnodes cache, then nothing to do */
1507cb5caa98Sdjl 			idx = get_cache_idx("ipnodes");
1508cb5caa98Sdjl 			if (cache_ctx_p[idx] == NULL ||
1509cb5caa98Sdjl 			    cache_ctx_p[idx]->reaper_on != nscd_true)
1510cb5caa98Sdjl 				break;
1511cb5caa98Sdjl 			nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1512cb5caa98Sdjl 			break;
1513cb5caa98Sdjl 		case RTM_ADD:
1514cb5caa98Sdjl 		case RTM_DELETE:
1515cb5caa98Sdjl 		case RTM_CHANGE:
1516cb5caa98Sdjl 		case RTM_GET:
1517cb5caa98Sdjl 		case RTM_LOSING:
1518cb5caa98Sdjl 		case RTM_REDIRECT:
1519cb5caa98Sdjl 		case RTM_MISS:
1520cb5caa98Sdjl 		case RTM_LOCK:
1521cb5caa98Sdjl 		case RTM_OLDADD:
1522cb5caa98Sdjl 		case RTM_OLDDEL:
1523cb5caa98Sdjl 		case RTM_RESOLVE:
1524cb5caa98Sdjl 		case RTM_IFINFO:
1525cb5caa98Sdjl 			break;
1526cb5caa98Sdjl 		default:
1527cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1528cb5caa98Sdjl 			(me, "rx unknown msg type (%d) on routing socket.\n",
1529cb5caa98Sdjl 			    ifam->ifam_type);
1530cb5caa98Sdjl 			break;
1531cb5caa98Sdjl 		}
1532cb5caa98Sdjl 	}
1533cb5caa98Sdjl }
1534cb5caa98Sdjl 
1535cb5caa98Sdjl static void
1536cb5caa98Sdjl keep_open_dns_socket(void)
1537cb5caa98Sdjl {
1538cb5caa98Sdjl 	_res.options |= RES_STAYOPEN; /* just keep this udp socket open */
1539cb5caa98Sdjl }
1540