xref: /titanic_52/usr/src/cmd/nscd/nscd_frontend.c (revision e37190e5b4531a897e4191a30b8f41678b582e25)
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 /*
22cb5caa98Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23cb5caa98Sdjl  * Use is subject to license terms.
24cb5caa98Sdjl  */
25cb5caa98Sdjl 
26cb5caa98Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27cb5caa98Sdjl 
28cb5caa98Sdjl #include <stdlib.h>
29cb5caa98Sdjl #include <alloca.h>
30cb5caa98Sdjl #include <signal.h>
31cb5caa98Sdjl #include <sys/stat.h>
32cb5caa98Sdjl #include <unistd.h>
33cb5caa98Sdjl #include <pthread.h>
34cb5caa98Sdjl #include <time.h>
35cb5caa98Sdjl #include <errno.h>
36cb5caa98Sdjl #include <door.h>
37cb5caa98Sdjl #include <zone.h>
38cb5caa98Sdjl #include <resolv.h>
39cb5caa98Sdjl #include <sys/socket.h>
40cb5caa98Sdjl #include <net/route.h>
41cb5caa98Sdjl #include <string.h>
42cb5caa98Sdjl #include <net/if.h>
43cb5caa98Sdjl #include <sys/stat.h>
44cb5caa98Sdjl #include <fcntl.h>
45cb5caa98Sdjl #include "nscd_common.h"
46cb5caa98Sdjl #include "nscd_door.h"
47cb5caa98Sdjl #include "nscd_config.h"
48cb5caa98Sdjl #include "nscd_switch.h"
49cb5caa98Sdjl #include "nscd_log.h"
50cb5caa98Sdjl #include "nscd_selfcred.h"
51cb5caa98Sdjl #include "nscd_frontend.h"
52cb5caa98Sdjl #include "nscd_admin.h"
53cb5caa98Sdjl 
54cb5caa98Sdjl static void rts_mon(void);
55cb5caa98Sdjl static void keep_open_dns_socket(void);
56cb5caa98Sdjl 
57cb5caa98Sdjl extern nsc_ctx_t *cache_ctx_p[];
58cb5caa98Sdjl 
59cb5caa98Sdjl /*
60cb5caa98Sdjl  * Current active Configuration data for the frontend component
61cb5caa98Sdjl  */
62cb5caa98Sdjl static nscd_cfg_global_frontend_t	frontend_cfg_g;
63cb5caa98Sdjl static nscd_cfg_frontend_t		*frontend_cfg;
64cb5caa98Sdjl 
65cb5caa98Sdjl static int	max_servers = 0;
66cb5caa98Sdjl static int	max_servers_set = 0;
67cb5caa98Sdjl static int	per_user_is_on = 1;
68cb5caa98Sdjl 
69cb5caa98Sdjl static char	*main_execname;
70cb5caa98Sdjl static char	**main_argv;
71cb5caa98Sdjl extern int	_whoami;
72cb5caa98Sdjl extern long	activity;
73cb5caa98Sdjl extern mutex_t	activity_lock;
74cb5caa98Sdjl 
75cb5caa98Sdjl static sema_t	common_sema;
76cb5caa98Sdjl 
77cb5caa98Sdjl static thread_key_t	lookup_state_key;
78cb5caa98Sdjl static mutex_t		create_lock = DEFAULTMUTEX;
79cb5caa98Sdjl static int		num_servers = 0;
80cb5caa98Sdjl static thread_key_t	server_key;
81cb5caa98Sdjl 
82cb5caa98Sdjl /*
83cb5caa98Sdjl  * Bind a TSD value to a server thread. This enables the destructor to
84cb5caa98Sdjl  * be called if/when this thread exits.  This would be a programming
85cb5caa98Sdjl  * error, but better safe than sorry.
86cb5caa98Sdjl  */
87cb5caa98Sdjl /*ARGSUSED*/
88cb5caa98Sdjl static void *
89cb5caa98Sdjl server_tsd_bind(void *arg)
90cb5caa98Sdjl {
91cb5caa98Sdjl 	static void *value = 0;
92cb5caa98Sdjl 
93cb5caa98Sdjl 	/* disable cancellation to avoid hangs if server threads disappear */
94cb5caa98Sdjl 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
95cb5caa98Sdjl 	(void) thr_setspecific(server_key, value);
96cb5caa98Sdjl 	(void) door_return(NULL, 0, NULL, 0);
97cb5caa98Sdjl 
98cb5caa98Sdjl 	/* make lint happy */
99cb5caa98Sdjl 	return (NULL);
100cb5caa98Sdjl }
101cb5caa98Sdjl 
102cb5caa98Sdjl /*
103cb5caa98Sdjl  * Server threads are created here.
104cb5caa98Sdjl  */
105cb5caa98Sdjl /*ARGSUSED*/
106cb5caa98Sdjl static void
107cb5caa98Sdjl server_create(door_info_t *dip)
108cb5caa98Sdjl {
109cb5caa98Sdjl 	(void) mutex_lock(&create_lock);
110cb5caa98Sdjl 	if (++num_servers > max_servers) {
111cb5caa98Sdjl 		num_servers--;
112cb5caa98Sdjl 		(void) mutex_unlock(&create_lock);
113cb5caa98Sdjl 		return;
114cb5caa98Sdjl 	}
115cb5caa98Sdjl 	(void) mutex_unlock(&create_lock);
116cb5caa98Sdjl 	(void) thr_create(NULL, 0, server_tsd_bind, NULL,
117cb5caa98Sdjl 			THR_BOUND|THR_DETACHED, NULL);
118cb5caa98Sdjl }
119cb5caa98Sdjl 
120cb5caa98Sdjl /*
121cb5caa98Sdjl  * Server thread are destroyed here
122cb5caa98Sdjl  */
123cb5caa98Sdjl /*ARGSUSED*/
124cb5caa98Sdjl static void
125cb5caa98Sdjl server_destroy(void *arg)
126cb5caa98Sdjl {
127cb5caa98Sdjl 	(void) mutex_lock(&create_lock);
128cb5caa98Sdjl 	num_servers--;
129cb5caa98Sdjl 	(void) mutex_unlock(&create_lock);
130cb5caa98Sdjl }
131cb5caa98Sdjl 
132cb5caa98Sdjl /*
133cb5caa98Sdjl  * get clearance
134cb5caa98Sdjl  */
135cb5caa98Sdjl int
136cb5caa98Sdjl _nscd_get_clearance(sema_t *sema) {
137cb5caa98Sdjl 	if (sema_trywait(&common_sema) == 0) {
138cb5caa98Sdjl 		(void) thr_setspecific(lookup_state_key, NULL);
139cb5caa98Sdjl 		return (0);
140cb5caa98Sdjl 	}
141cb5caa98Sdjl 
142cb5caa98Sdjl 	if (sema_trywait(sema) == 0) {
143cb5caa98Sdjl 		(void) thr_setspecific(lookup_state_key, (void*)1);
144cb5caa98Sdjl 		return (0);
145cb5caa98Sdjl 	}
146cb5caa98Sdjl 
147cb5caa98Sdjl 	return (1);
148cb5caa98Sdjl }
149cb5caa98Sdjl 
150cb5caa98Sdjl 
151cb5caa98Sdjl /*
152cb5caa98Sdjl  * release clearance
153cb5caa98Sdjl  */
154cb5caa98Sdjl int
155cb5caa98Sdjl _nscd_release_clearance(sema_t *sema) {
156cb5caa98Sdjl 	int	which;
157cb5caa98Sdjl 
158cb5caa98Sdjl 	(void) thr_getspecific(lookup_state_key, (void**)&which);
159cb5caa98Sdjl 	if (which == 0) /* from common pool */ {
160cb5caa98Sdjl 		(void) sema_post(&common_sema);
161cb5caa98Sdjl 		return (0);
162cb5caa98Sdjl 	}
163cb5caa98Sdjl 
164cb5caa98Sdjl 	(void) sema_post(sema);
165cb5caa98Sdjl 	return (1);
166cb5caa98Sdjl }
167cb5caa98Sdjl 
168cb5caa98Sdjl static void
169cb5caa98Sdjl dozip(void)
170cb5caa98Sdjl {
171cb5caa98Sdjl 	/* not much here */
172cb5caa98Sdjl }
173cb5caa98Sdjl 
174cb5caa98Sdjl static void
175cb5caa98Sdjl restart_if_cfgfile_changed()
176cb5caa98Sdjl {
177cb5caa98Sdjl 
178cb5caa98Sdjl 	static mutex_t	nsswitch_lock = DEFAULTMUTEX;
179cb5caa98Sdjl 	static time_t	last_nsswitch_check = 0;
180cb5caa98Sdjl 	static time_t	last_nsswitch_modified = 0;
181cb5caa98Sdjl 	static time_t	last_resolv_modified = 0;
182cb5caa98Sdjl 	time_t		now = time(NULL);
183cb5caa98Sdjl 	char		*me = "restart_if_cfgfile_changed";
184cb5caa98Sdjl 
185cb5caa98Sdjl 	if (now - last_nsswitch_check <= _NSC_FILE_CHECK_TIME)
186cb5caa98Sdjl 		return;
187cb5caa98Sdjl 
188cb5caa98Sdjl 	(void) mutex_lock(&nsswitch_lock);
189cb5caa98Sdjl 
190cb5caa98Sdjl 	if (now - last_nsswitch_check > _NSC_FILE_CHECK_TIME) {
191cb5caa98Sdjl 		struct stat nss_buf;
192cb5caa98Sdjl 		struct stat res_buf;
193cb5caa98Sdjl 
194cb5caa98Sdjl 		last_nsswitch_check = now;
195cb5caa98Sdjl 
196cb5caa98Sdjl 		(void) mutex_unlock(&nsswitch_lock); /* let others continue */
197cb5caa98Sdjl 
198cb5caa98Sdjl 		/*
199cb5caa98Sdjl 		 *  This code keeps us from statting resolv.conf
200cb5caa98Sdjl 		 *  if it doesn't exist, yet prevents us from ignoring
201cb5caa98Sdjl 		 *  it if it happens to disappear later on for a bit.
202cb5caa98Sdjl 		 */
203cb5caa98Sdjl 
204cb5caa98Sdjl 		if (last_resolv_modified >= 0) {
205cb5caa98Sdjl 			if (stat("/etc/resolv.conf", &res_buf) < 0) {
206cb5caa98Sdjl 				if (last_resolv_modified == 0)
207cb5caa98Sdjl 				    last_resolv_modified = -1;
208cb5caa98Sdjl 				else
209cb5caa98Sdjl 				    res_buf.st_mtime = last_resolv_modified;
210cb5caa98Sdjl 			} else if (last_resolv_modified == 0) {
211cb5caa98Sdjl 			    last_resolv_modified = res_buf.st_mtime;
212cb5caa98Sdjl 			}
213cb5caa98Sdjl 		}
214cb5caa98Sdjl 
215cb5caa98Sdjl 		if (stat("/etc/nsswitch.conf", &nss_buf) < 0) {
216cb5caa98Sdjl 
217cb5caa98Sdjl 			/*EMPTY*/;
218cb5caa98Sdjl 
219cb5caa98Sdjl 		} else if (last_nsswitch_modified == 0) {
220cb5caa98Sdjl 
221cb5caa98Sdjl 			last_nsswitch_modified = nss_buf.st_mtime;
222cb5caa98Sdjl 
223cb5caa98Sdjl 		} else if ((last_nsswitch_modified < nss_buf.st_mtime) ||
224cb5caa98Sdjl 		    ((last_resolv_modified > 0) &&
225cb5caa98Sdjl 		    (last_resolv_modified < res_buf.st_mtime))) {
226cb5caa98Sdjl 			static mutex_t exit_lock = DEFAULTMUTEX;
227cb5caa98Sdjl 			char *fmri;
228cb5caa98Sdjl 
229cb5caa98Sdjl 			/*
230cb5caa98Sdjl 			 * if in self cred mode, kill the forker and
231cb5caa98Sdjl 			 * child nscds
232cb5caa98Sdjl 			 */
233cb5caa98Sdjl 			if (_nscd_is_self_cred_on(0, NULL)) {
234cb5caa98Sdjl 				_nscd_kill_forker();
235cb5caa98Sdjl 				_nscd_kill_all_children();
236cb5caa98Sdjl 			}
237cb5caa98Sdjl 
238cb5caa98Sdjl 			/*
239cb5caa98Sdjl 			 * time for restart
240cb5caa98Sdjl 			 */
241cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
242cb5caa98Sdjl 			(me, "nscd restart due to %s or %s change\n",
243cb5caa98Sdjl 				"/etc/nsswitch.conf", "resolv.conf");
244cb5caa98Sdjl 			/*
245cb5caa98Sdjl 			 * try to restart under smf
246cb5caa98Sdjl 			 */
247cb5caa98Sdjl 			if ((fmri = getenv("SMF_FMRI")) == NULL) {
248cb5caa98Sdjl 				/* not running under smf - reexec */
249cb5caa98Sdjl 				(void) execv(main_execname, main_argv);
250cb5caa98Sdjl 				exit(1); /* just in case */
251cb5caa98Sdjl 			}
252cb5caa98Sdjl 
253cb5caa98Sdjl 			/* prevent multiple restarts */
254cb5caa98Sdjl 			(void) mutex_lock(&exit_lock);
255cb5caa98Sdjl 
256cb5caa98Sdjl 			if (smf_restart_instance(fmri) == 0)
257cb5caa98Sdjl 				(void) sleep(10); /* wait a bit */
258cb5caa98Sdjl 			exit(1); /* give up waiting for resurrection */
259cb5caa98Sdjl 		}
260cb5caa98Sdjl 
261cb5caa98Sdjl 	} else
262cb5caa98Sdjl 	    (void) mutex_unlock(&nsswitch_lock);
263cb5caa98Sdjl }
264cb5caa98Sdjl 
265cb5caa98Sdjl uid_t
266cb5caa98Sdjl _nscd_get_client_euid()
267cb5caa98Sdjl {
268cb5caa98Sdjl 	ucred_t	*uc = NULL;
269cb5caa98Sdjl 	uid_t	id;
270cb5caa98Sdjl 	char	*me = "get_client_euid";
271cb5caa98Sdjl 
272cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
273cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
274cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
275cb5caa98Sdjl 		return ((uid_t)-1);
276cb5caa98Sdjl 	}
277cb5caa98Sdjl 
278cb5caa98Sdjl 	id = ucred_geteuid(uc);
279cb5caa98Sdjl 	ucred_free(uc);
280cb5caa98Sdjl 	return (id);
281cb5caa98Sdjl }
282cb5caa98Sdjl 
283cb5caa98Sdjl static void
284cb5caa98Sdjl N2N_check_priv(
285cb5caa98Sdjl 	void			*buf,
286cb5caa98Sdjl 	char			*dc_str)
287cb5caa98Sdjl {
288cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)buf;
289cb5caa98Sdjl 	ucred_t			*uc = NULL;
290cb5caa98Sdjl 	const priv_set_t	*eset;
291cb5caa98Sdjl 	zoneid_t		zoneid;
292cb5caa98Sdjl 	int			errnum;
293cb5caa98Sdjl 	char			*me = "N2N_check_priv";
294cb5caa98Sdjl 
295cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
296cb5caa98Sdjl 		errnum = errno;
297cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
298cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
299cb5caa98Sdjl 
300cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
301cb5caa98Sdjl 	}
302cb5caa98Sdjl 
303cb5caa98Sdjl 	eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
304cb5caa98Sdjl 	zoneid = ucred_getzoneid(uc);
305cb5caa98Sdjl 
306cb5caa98Sdjl 	if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
307cb5caa98Sdjl 		eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
308cb5caa98Sdjl 		ucred_geteuid(uc) != 0) {
309cb5caa98Sdjl 
310cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
311cb5caa98Sdjl 		(me, "%s call failed(cred): caller pid %d, uid %d, "
312cb5caa98Sdjl 		"euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
313cb5caa98Sdjl 		ucred_getruid(uc), ucred_geteuid(uc), zoneid);
314cb5caa98Sdjl 		ucred_free(uc);
315cb5caa98Sdjl 
316cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES);
317cb5caa98Sdjl 	}
318cb5caa98Sdjl 
319cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
320cb5caa98Sdjl 	(me, "nscd received %s cmd from pid %d, uid %d, "
321cb5caa98Sdjl 	"euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
322cb5caa98Sdjl 	ucred_getruid(uc), ucred_geteuid(uc), zoneid);
323cb5caa98Sdjl 
324cb5caa98Sdjl 	ucred_free(uc);
325cb5caa98Sdjl 
326cb5caa98Sdjl 	NSCD_RETURN_STATUS_SUCCESS(phdr);
327cb5caa98Sdjl }
328cb5caa98Sdjl 
329*e37190e5Smichen void
330*e37190e5Smichen _nscd_APP_check_cred(
331cb5caa98Sdjl 	void		*buf,
332cb5caa98Sdjl 	pid_t		*pidp,
333*e37190e5Smichen 	char		*dc_str,
334*e37190e5Smichen 	int		log_comp,
335*e37190e5Smichen 	int		log_level)
336cb5caa98Sdjl {
337cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
338cb5caa98Sdjl 	ucred_t		*uc = NULL;
339cb5caa98Sdjl 	uid_t		ruid;
340cb5caa98Sdjl 	uid_t		euid;
341*e37190e5Smichen 	pid_t		pid;
342cb5caa98Sdjl 	int		errnum;
343*e37190e5Smichen 	char		*me = "_nscd_APP_check_cred";
344cb5caa98Sdjl 
345cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
346cb5caa98Sdjl 		errnum = errno;
347*e37190e5Smichen 		_NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
348cb5caa98Sdjl 		(me, "door_ucred: %s\n", strerror(errno));
349cb5caa98Sdjl 
350cb5caa98Sdjl 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
351cb5caa98Sdjl 	}
352cb5caa98Sdjl 
353*e37190e5Smichen 	NSCD_SET_STATUS_SUCCESS(phdr);
354*e37190e5Smichen 	pid = ucred_getpid(uc);
355cb5caa98Sdjl 	if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
356cb5caa98Sdjl 		euid = ucred_geteuid(uc))) {
357*e37190e5Smichen 		if (pidp != NULL) {
358*e37190e5Smichen 			if (*pidp == (pid_t)-1)
359*e37190e5Smichen 				*pidp = pid;
360*e37190e5Smichen 			else if (*pidp != pid) {
361*e37190e5Smichen 				NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
362*e37190e5Smichen 			}
363*e37190e5Smichen 		}
364*e37190e5Smichen 	} else {
365*e37190e5Smichen 		NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
366cb5caa98Sdjl 	}
367cb5caa98Sdjl 
368cb5caa98Sdjl 	ucred_free(uc);
369cb5caa98Sdjl 
370*e37190e5Smichen 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
371*e37190e5Smichen 		_NSCD_LOG(log_comp, log_level)
372*e37190e5Smichen 		(me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
373*e37190e5Smichen 		"euid %d, header ruid %d, header euid %d\n", dc_str,
374*e37190e5Smichen 		pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
375*e37190e5Smichen 		((nss_pheader_t *)(buf))->p_ruid,
376*e37190e5Smichen 		((nss_pheader_t *)(buf))->p_euid);
377*e37190e5Smichen 	}
378cb5caa98Sdjl }
379cb5caa98Sdjl 
380cb5caa98Sdjl static void
381cb5caa98Sdjl lookup(char *argp, size_t arg_size)
382cb5caa98Sdjl {
383cb5caa98Sdjl 	nsc_lookup_args_t	largs;
384cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
385cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
386cb5caa98Sdjl 
387cb5caa98Sdjl 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
388cb5caa98Sdjl 		sizeof (space));
389cb5caa98Sdjl 
390cb5caa98Sdjl 	(void) memset(&largs, 0, sizeof (largs));
391cb5caa98Sdjl 	largs.buffer = argp;
392cb5caa98Sdjl 	largs.bufsize = arg_size;
393cb5caa98Sdjl 	nsc_lookup(&largs, 0);
394cb5caa98Sdjl 
395cb5caa98Sdjl 	/*
396cb5caa98Sdjl 	 * only the PUN needs to keep track of the
397cb5caa98Sdjl 	 * activity count to determine when to
398cb5caa98Sdjl 	 * terminate itself
399cb5caa98Sdjl 	 */
400cb5caa98Sdjl 	if (_whoami == NSCD_CHILD) {
401cb5caa98Sdjl 		(void) mutex_lock(&activity_lock);
402cb5caa98Sdjl 		++activity;
403cb5caa98Sdjl 		(void) mutex_unlock(&activity_lock);
404cb5caa98Sdjl 	}
405cb5caa98Sdjl 
406cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
407cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
408cb5caa98Sdjl }
409cb5caa98Sdjl 
410cb5caa98Sdjl static void
411cb5caa98Sdjl getent(char *argp, size_t arg_size)
412cb5caa98Sdjl {
413cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
414cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
415cb5caa98Sdjl 
416cb5caa98Sdjl 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr,
417cb5caa98Sdjl 		space, sizeof (space));
418cb5caa98Sdjl 
419cb5caa98Sdjl 	nss_pgetent(argp, arg_size);
420cb5caa98Sdjl 
421cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
422cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
423cb5caa98Sdjl }
424cb5caa98Sdjl 
425cb5caa98Sdjl static int
426cb5caa98Sdjl is_db_per_user(void *buf, char *dblist)
427cb5caa98Sdjl {
428cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
429cb5caa98Sdjl 	nss_dbd_t	*pdbd;
430cb5caa98Sdjl 	char		*dbname, *dbn;
431cb5caa98Sdjl 	int		len;
432cb5caa98Sdjl 
433cb5caa98Sdjl 	/* copy db name into a temp buffer */
434cb5caa98Sdjl 	pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
435cb5caa98Sdjl 	dbname = (char *)pdbd + pdbd->o_name;
436cb5caa98Sdjl 	len = strlen(dbname);
437cb5caa98Sdjl 	dbn = alloca(len + 2);
438cb5caa98Sdjl 	(void) memcpy(dbn, dbname, len);
439cb5caa98Sdjl 
440cb5caa98Sdjl 	/* check if <dbname> + ',' can be found in the dblist string */
441cb5caa98Sdjl 	dbn[len] = ',';
442cb5caa98Sdjl 	dbn[len + 1] = '\0';
443cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
444cb5caa98Sdjl 		return (1);
445cb5caa98Sdjl 
446cb5caa98Sdjl 	/*
447cb5caa98Sdjl 	 * check if <dbname> can be found in the last part
448cb5caa98Sdjl 	 * of the dblist string
449cb5caa98Sdjl 	 */
450cb5caa98Sdjl 	dbn[len] = '\0';
451cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
452cb5caa98Sdjl 		return (1);
453cb5caa98Sdjl 
454cb5caa98Sdjl 	return (0);
455cb5caa98Sdjl }
456cb5caa98Sdjl 
457cb5caa98Sdjl /*
458cb5caa98Sdjl  * Check to see if all conditions are met for processing per-user
459cb5caa98Sdjl  * requests. Returns 1 if yes, -1 if backend is not configured,
460cb5caa98Sdjl  * 0 otherwise.
461cb5caa98Sdjl  */
462cb5caa98Sdjl static int
463cb5caa98Sdjl need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
464cb5caa98Sdjl {
465cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
466cb5caa98Sdjl 
467cb5caa98Sdjl 	NSCD_SET_STATUS_SUCCESS(phdr);
468cb5caa98Sdjl 
469cb5caa98Sdjl 	/* if already a per-user nscd, no need to get per-user door */
470cb5caa98Sdjl 	if (whoami == NSCD_CHILD)
471cb5caa98Sdjl 		return (0);
472cb5caa98Sdjl 
473cb5caa98Sdjl 	/* forker shouldn't be asked */
474cb5caa98Sdjl 	if (whoami == NSCD_FORKER) {
475cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
476cb5caa98Sdjl 		return (0);
477cb5caa98Sdjl 	}
478cb5caa98Sdjl 
479cb5caa98Sdjl 	/* if door client is root, no need for a per-user door */
480cb5caa98Sdjl 	if (uid == 0)
481cb5caa98Sdjl 		return (0);
482cb5caa98Sdjl 
483cb5caa98Sdjl 	/*
484cb5caa98Sdjl 	 * if per-user lookup is not configured, no per-user
485cb5caa98Sdjl 	 * door available
486cb5caa98Sdjl 	 */
487cb5caa98Sdjl 	if (_nscd_is_self_cred_on(0, dblist) == 0)
488cb5caa98Sdjl 		return (-1);
489cb5caa98Sdjl 
490cb5caa98Sdjl 	/*
491cb5caa98Sdjl 	 * if per-user lookup is not configured for the db,
492cb5caa98Sdjl 	 * don't bother
493cb5caa98Sdjl 	 */
494cb5caa98Sdjl 	if (is_db_per_user(phdr, *dblist) == 0)
495cb5caa98Sdjl 		return (0);
496cb5caa98Sdjl 
497cb5caa98Sdjl 	return (1);
498cb5caa98Sdjl }
499cb5caa98Sdjl 
500cb5caa98Sdjl static void
501cb5caa98Sdjl if_selfcred_return_per_user_door(char *argp, size_t arg_size,
502cb5caa98Sdjl 	door_desc_t *dp, int whoami)
503cb5caa98Sdjl {
504cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)((void *)argp);
505cb5caa98Sdjl 	char		*dblist;
506cb5caa98Sdjl 	int		door = -1;
507cb5caa98Sdjl 	int		rc = 0;
508cb5caa98Sdjl 	door_desc_t	desc;
509cb5caa98Sdjl 	char		space[1024*4];
510cb5caa98Sdjl 
511cb5caa98Sdjl 	/*
512cb5caa98Sdjl 	 * check to see if self-cred is configured and
513cb5caa98Sdjl 	 * need to return an alternate PUN door
514cb5caa98Sdjl 	 */
515cb5caa98Sdjl 	if (per_user_is_on == 1) {
516cb5caa98Sdjl 		rc = need_per_user_door(argp, whoami,
517cb5caa98Sdjl 			_nscd_get_client_euid(), &dblist);
518cb5caa98Sdjl 		if (rc == -1)
519cb5caa98Sdjl 			per_user_is_on = 0;
520cb5caa98Sdjl 	}
521cb5caa98Sdjl 	if (rc <= 0) {
522cb5caa98Sdjl 		/*
523cb5caa98Sdjl 		 * self-cred not configured, and no error detected,
524cb5caa98Sdjl 		 * return to continue the door call processing
525cb5caa98Sdjl 		 */
526cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
527cb5caa98Sdjl 			return;
528cb5caa98Sdjl 		else
529cb5caa98Sdjl 			/*
530cb5caa98Sdjl 			 * configured but error detected,
531cb5caa98Sdjl 			 * stop the door call processing
532cb5caa98Sdjl 			 */
533cb5caa98Sdjl 			(void) door_return(argp, phdr->data_off, NULL, 0);
534cb5caa98Sdjl 	}
535cb5caa98Sdjl 
536cb5caa98Sdjl 	/* get the alternate PUN door */
537cb5caa98Sdjl 	_nscd_proc_alt_get(argp, &door);
538cb5caa98Sdjl 	if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
539cb5caa98Sdjl 		(void) door_return(argp, phdr->data_off, NULL, 0);
540cb5caa98Sdjl 	}
541cb5caa98Sdjl 
542cb5caa98Sdjl 	/* return the alternate door descriptor */
543cb5caa98Sdjl 	(void) memcpy(space, phdr, NSCD_PHDR_LEN(phdr));
544cb5caa98Sdjl 	argp = space;
545cb5caa98Sdjl 	phdr = (nss_pheader_t *)(void *)space;
546cb5caa98Sdjl 	dp = &desc;
547cb5caa98Sdjl 	dp->d_attributes = DOOR_DESCRIPTOR;
548cb5caa98Sdjl 	dp->d_data.d_desc.d_descriptor = door;
549cb5caa98Sdjl 	phdr->data_len = strlen(dblist) + 1;
550cb5caa98Sdjl 	(void) strcpy(((char *)phdr) + NSCD_PHDR_LEN(phdr), dblist);
551cb5caa98Sdjl 
552cb5caa98Sdjl 	arg_size = NSCD_PHDR_LEN(phdr) + NSCD_DATA_LEN(phdr);
553cb5caa98Sdjl 	(void) door_return(argp, arg_size, dp, 1);
554cb5caa98Sdjl }
555cb5caa98Sdjl 
556cb5caa98Sdjl /*ARGSUSED*/
557cb5caa98Sdjl static void
558cb5caa98Sdjl switcher(void *cookie, char *argp, size_t arg_size,
559cb5caa98Sdjl     door_desc_t *dp, uint_t n_desc)
560cb5caa98Sdjl {
561cb5caa98Sdjl 	int			iam;
562cb5caa98Sdjl 	pid_t			ent_pid = -1;
563cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)((void *)argp);
564cb5caa98Sdjl 	void			*uptr;
565cb5caa98Sdjl 	int			buflen, len;
566cb5caa98Sdjl 	int			callnum;
567cb5caa98Sdjl 	char			*me = "switcher";
568cb5caa98Sdjl 
569cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
570cb5caa98Sdjl 	(me, "switcher ...\n");
571cb5caa98Sdjl 
572cb5caa98Sdjl 	if (argp == DOOR_UNREF_DATA) {
573cb5caa98Sdjl 		(void) printf("Door Slam... exiting\n");
574cb5caa98Sdjl 		exit(0);
575cb5caa98Sdjl 	}
576cb5caa98Sdjl 
577cb5caa98Sdjl 	if (argp == NULL) { /* empty door call */
578cb5caa98Sdjl 		(void) door_return(NULL, 0, 0, 0); /* return the favor */
579cb5caa98Sdjl 	}
580cb5caa98Sdjl 
581cb5caa98Sdjl 	/*
582cb5caa98Sdjl 	 *  need to restart if main nscd and config file(s) changed
583cb5caa98Sdjl 	 */
584cb5caa98Sdjl 	if (_whoami == NSCD_MAIN)
585cb5caa98Sdjl 		restart_if_cfgfile_changed();
586cb5caa98Sdjl 
587cb5caa98Sdjl 	if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
588cb5caa98Sdjl 		switch (phdr->nsc_callnumber) {
589cb5caa98Sdjl 		case NSCD_SEARCH:
590cb5caa98Sdjl 
591cb5caa98Sdjl 		/* if a fallback to main nscd, skip per-user setup */
592cb5caa98Sdjl 		if (phdr->p_status != NSS_ALTRETRY)
593cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
594cb5caa98Sdjl 				dp, _whoami);
595cb5caa98Sdjl 		lookup(argp, arg_size);
596cb5caa98Sdjl 
597cb5caa98Sdjl 		break;
598cb5caa98Sdjl 
599cb5caa98Sdjl 		case NSCD_SETENT:
600cb5caa98Sdjl 
601*e37190e5Smichen 		_nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
602*e37190e5Smichen 			NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
603cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
604cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
605cb5caa98Sdjl 				dp, _whoami);
606cb5caa98Sdjl 			nss_psetent(argp, arg_size, ent_pid);
607cb5caa98Sdjl 		}
608cb5caa98Sdjl 		break;
609cb5caa98Sdjl 
610cb5caa98Sdjl 		case NSCD_GETENT:
611cb5caa98Sdjl 
612cb5caa98Sdjl 		getent(argp, arg_size);
613cb5caa98Sdjl 		break;
614cb5caa98Sdjl 
615cb5caa98Sdjl 		case NSCD_ENDENT:
616cb5caa98Sdjl 
617cb5caa98Sdjl 		nss_pendent(argp, arg_size);
618cb5caa98Sdjl 		break;
619cb5caa98Sdjl 
620cb5caa98Sdjl 		case NSCD_PUT:
621cb5caa98Sdjl 
622cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
623cb5caa98Sdjl 		(me, "door call NSCD_PUT not supported yet\n");
624cb5caa98Sdjl 
625cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
626cb5caa98Sdjl 		break;
627cb5caa98Sdjl 
628cb5caa98Sdjl 		case NSCD_GETHINTS:
629cb5caa98Sdjl 
630cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
631cb5caa98Sdjl 		(me, "door call NSCD_GETHINTS not supported yet\n");
632cb5caa98Sdjl 
633cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
634cb5caa98Sdjl 		break;
635cb5caa98Sdjl 
636cb5caa98Sdjl 		default:
637cb5caa98Sdjl 
638cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
639cb5caa98Sdjl 		(me, "Unknown name service door call op %x\n",
640cb5caa98Sdjl 		phdr->nsc_callnumber);
641cb5caa98Sdjl 
642cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
643cb5caa98Sdjl 		break;
644cb5caa98Sdjl 		}
645cb5caa98Sdjl 
646cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
647cb5caa98Sdjl 	}
648cb5caa98Sdjl 
649cb5caa98Sdjl 	iam = NSCD_MAIN;
650cb5caa98Sdjl 	callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
651cb5caa98Sdjl 	if (callnum == NSCD_IMHERE ||
652cb5caa98Sdjl 		callnum == NSCD_PULSE || callnum == NSCD_FORK)
653cb5caa98Sdjl 		iam = phdr->nsc_callnumber & NSCD_WHOAMI;
654cb5caa98Sdjl 	else
655cb5caa98Sdjl 		callnum = phdr->nsc_callnumber;
656cb5caa98Sdjl 
657cb5caa98Sdjl 	/* nscd -> nscd v2 calls */
658cb5caa98Sdjl 	switch (callnum) {
659cb5caa98Sdjl 
660cb5caa98Sdjl 	case NSCD_PING:
661cb5caa98Sdjl 		NSCD_SET_STATUS_SUCCESS(phdr);
662cb5caa98Sdjl 		break;
663cb5caa98Sdjl 
664cb5caa98Sdjl 	case NSCD_IMHERE:
665cb5caa98Sdjl 		_nscd_proc_iamhere(argp, dp, n_desc, iam);
666cb5caa98Sdjl 		break;
667cb5caa98Sdjl 
668cb5caa98Sdjl 	case NSCD_PULSE:
669cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_PULSE");
670cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
671cb5caa98Sdjl 			_nscd_proc_pulse(argp, iam);
672cb5caa98Sdjl 		break;
673cb5caa98Sdjl 
674cb5caa98Sdjl 	case NSCD_FORK:
675cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_FORK");
676cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
677cb5caa98Sdjl 			_nscd_proc_fork(argp, iam);
678cb5caa98Sdjl 		break;
679cb5caa98Sdjl 
680cb5caa98Sdjl 	case NSCD_KILL:
681cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILL");
682cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
683cb5caa98Sdjl 			exit(0);
684cb5caa98Sdjl 		break;
685cb5caa98Sdjl 
686cb5caa98Sdjl 	case NSCD_REFRESH:
687cb5caa98Sdjl 		if (_nscd_refresh() != NSCD_SUCCESS)
688cb5caa98Sdjl 			exit(1);
689cb5caa98Sdjl 		NSCD_SET_STATUS_SUCCESS(phdr);
690cb5caa98Sdjl 		break;
691cb5caa98Sdjl 
692cb5caa98Sdjl 	case NSCD_GETPUADMIN:
693cb5caa98Sdjl 
694cb5caa98Sdjl 		if (_nscd_is_self_cred_on(0, NULL)) {
695cb5caa98Sdjl 			_nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
696cb5caa98Sdjl 		} else {
697cb5caa98Sdjl 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
698cb5caa98Sdjl 				NSCD_SELF_CRED_NOT_CONFIGURED);
699cb5caa98Sdjl 		}
700cb5caa98Sdjl 		break;
701cb5caa98Sdjl 
702cb5caa98Sdjl 	case NSCD_GETADMIN:
703cb5caa98Sdjl 
704cb5caa98Sdjl 		len = _nscd_door_getadmin((void *)argp);
705cb5caa98Sdjl 		if (len == 0)
706cb5caa98Sdjl 			break;
707cb5caa98Sdjl 
708cb5caa98Sdjl 		/* size of door buffer not big enough, allocate one */
709cb5caa98Sdjl 		NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
710cb5caa98Sdjl 
711cb5caa98Sdjl 		/* copy packed header */
712cb5caa98Sdjl 		*(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
713cb5caa98Sdjl 
714cb5caa98Sdjl 		/* set new buffer size */
715cb5caa98Sdjl 		((nss_pheader_t *)uptr)->pbufsiz = buflen;
716cb5caa98Sdjl 
717cb5caa98Sdjl 		/* try one more time */
718cb5caa98Sdjl 		(void) _nscd_door_getadmin((void *)uptr);
719cb5caa98Sdjl 		(void) door_return(uptr, buflen, NULL, 0);
720cb5caa98Sdjl 		break;
721cb5caa98Sdjl 
722cb5caa98Sdjl 	case NSCD_SETADMIN:
723cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_SETADMIN");
724cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
725cb5caa98Sdjl 			_nscd_door_setadmin(argp);
726cb5caa98Sdjl 		break;
727cb5caa98Sdjl 
728cb5caa98Sdjl 	case NSCD_KILLSERVER:
729cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILLSERVER");
730cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
731cb5caa98Sdjl 			/* also kill the forker nscd if one is running */
732cb5caa98Sdjl 			_nscd_kill_forker();
733cb5caa98Sdjl 			exit(0);
734cb5caa98Sdjl 		}
735cb5caa98Sdjl 		break;
736cb5caa98Sdjl 
737cb5caa98Sdjl 	default:
738cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
739cb5caa98Sdjl 		(me, "Unknown name service door call op %d\n",
740cb5caa98Sdjl 			phdr->nsc_callnumber);
741cb5caa98Sdjl 
742cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
743cb5caa98Sdjl 
744cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
745cb5caa98Sdjl 		break;
746cb5caa98Sdjl 
747cb5caa98Sdjl 	}
748cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
749cb5caa98Sdjl }
750cb5caa98Sdjl 
751cb5caa98Sdjl int
752cb5caa98Sdjl _nscd_setup_server(char *execname, char **argv)
753cb5caa98Sdjl {
754cb5caa98Sdjl 
755cb5caa98Sdjl 	int		fd;
756cb5caa98Sdjl 	int		errnum;
757cb5caa98Sdjl 	int		bind_failed = 0;
758cb5caa98Sdjl 	struct stat	buf;
759cb5caa98Sdjl 	sigset_t	myset;
760cb5caa98Sdjl 	struct sigaction action;
761cb5caa98Sdjl 	char		*me = "_nscd_setup_server";
762cb5caa98Sdjl 
763cb5caa98Sdjl 	main_execname = execname;
764cb5caa98Sdjl 	main_argv = argv;
765cb5caa98Sdjl 
766cb5caa98Sdjl 	keep_open_dns_socket();
767cb5caa98Sdjl 
768cb5caa98Sdjl 	/*
769cb5caa98Sdjl 	 * the max number of server threads should be fixed now, so
770cb5caa98Sdjl 	 * set flag to indicate that no in-flight change is allowed
771cb5caa98Sdjl 	 */
772cb5caa98Sdjl 	max_servers_set = 1;
773cb5caa98Sdjl 
774cb5caa98Sdjl 	(void) thr_keycreate(&lookup_state_key, NULL);
775cb5caa98Sdjl 	(void) sema_init(&common_sema,
776cb5caa98Sdjl 			frontend_cfg_g.common_worker_threads,
777cb5caa98Sdjl 			USYNC_THREAD, 0);
778cb5caa98Sdjl 
779cb5caa98Sdjl 	/* Establish server thread pool */
780cb5caa98Sdjl 	(void) door_server_create(server_create);
781cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
782cb5caa98Sdjl 		errnum = errno;
783cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
784cb5caa98Sdjl 		(me, "thr_keycreate (server thread): %s\n",
785cb5caa98Sdjl 			strerror(errnum));
786cb5caa98Sdjl 		return (-1);
787cb5caa98Sdjl 	}
788cb5caa98Sdjl 
789cb5caa98Sdjl 	/* Create a door */
790cb5caa98Sdjl 	if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
791cb5caa98Sdjl 	    DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
792cb5caa98Sdjl 		errnum = errno;
793cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
794cb5caa98Sdjl 		(me, "door_create: %s\n", strerror(errnum));
795cb5caa98Sdjl 		return (-1);
796cb5caa98Sdjl 	}
797cb5caa98Sdjl 
798cb5caa98Sdjl 	/* if not main nscd, no more setup to do */
799cb5caa98Sdjl 	if (_whoami != NSCD_MAIN)
800cb5caa98Sdjl 		return (fd);
801cb5caa98Sdjl 
802cb5caa98Sdjl 	/* bind to file system */
803cb5caa98Sdjl 	if (is_system_labeled()) {
804cb5caa98Sdjl 		if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
805cb5caa98Sdjl 			int newfd;
806cb5caa98Sdjl 			if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
807cb5caa98Sdjl 				errnum = errno;
808cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
809cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
810cb5caa98Sdjl 				(me, "Cannot create %s: %s\n",
811cb5caa98Sdjl 					TSOL_NAME_SERVICE_DOOR,
812cb5caa98Sdjl 					strerror(errnum));
813cb5caa98Sdjl 				bind_failed = 1;
814cb5caa98Sdjl 			}
815cb5caa98Sdjl 			(void) close(newfd);
816cb5caa98Sdjl 		}
817cb5caa98Sdjl 		if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
818cb5caa98Sdjl 			if (errno != EEXIST) {
819cb5caa98Sdjl 				errnum = errno;
820cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
821cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
822cb5caa98Sdjl 				(me, "Cannot symlink %s: %s\n",
823cb5caa98Sdjl 					NAME_SERVICE_DOOR,
824cb5caa98Sdjl 					strerror(errnum));
825cb5caa98Sdjl 				bind_failed = 1;
826cb5caa98Sdjl 			}
827cb5caa98Sdjl 		}
828cb5caa98Sdjl 	} else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
829cb5caa98Sdjl 		int newfd;
830cb5caa98Sdjl 		if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
831cb5caa98Sdjl 			errnum = errno;
832cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
833cb5caa98Sdjl 			(me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
834cb5caa98Sdjl 				strerror(errnum));
835cb5caa98Sdjl 			bind_failed = 1;
836cb5caa98Sdjl 		}
837cb5caa98Sdjl 		(void) close(newfd);
838cb5caa98Sdjl 	}
839cb5caa98Sdjl 
840cb5caa98Sdjl 	if (bind_failed == 1) {
841cb5caa98Sdjl 		(void) door_revoke(fd);
842cb5caa98Sdjl 		return (-1);
843cb5caa98Sdjl 	}
844cb5caa98Sdjl 
845cb5caa98Sdjl 	if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
846cb5caa98Sdjl 		if ((errno != EBUSY) ||
847cb5caa98Sdjl 		(fdetach(NAME_SERVICE_DOOR) <  0) ||
848cb5caa98Sdjl 		(fattach(fd, NAME_SERVICE_DOOR) < 0)) {
849cb5caa98Sdjl 			errnum = errno;
850cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END,
851cb5caa98Sdjl 				NSCD_LOG_LEVEL_ERROR)
852cb5caa98Sdjl 			(me, "fattach: %s\n", strerror(errnum));
853cb5caa98Sdjl 			(void) door_revoke(fd);
854cb5caa98Sdjl 			return (-1);
855cb5caa98Sdjl 		}
856cb5caa98Sdjl 	}
857cb5caa98Sdjl 
858cb5caa98Sdjl 	/*
859cb5caa98Sdjl 	 * kick off routing socket monitor thread
860cb5caa98Sdjl 	 */
861cb5caa98Sdjl 	if (thr_create(NULL, NULL,
862cb5caa98Sdjl 		(void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
863cb5caa98Sdjl 		errnum = errno;
864cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
865cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
866cb5caa98Sdjl 			strerror(errnum));
867cb5caa98Sdjl 
868cb5caa98Sdjl 		(void) door_revoke(fd);
869cb5caa98Sdjl 		return (-1);
870cb5caa98Sdjl 	}
871cb5caa98Sdjl 
872cb5caa98Sdjl 	/*
873cb5caa98Sdjl 	 * set up signal handler for SIGHUP
874cb5caa98Sdjl 	 */
875cb5caa98Sdjl 	action.sa_handler = dozip;
876cb5caa98Sdjl 	action.sa_flags = 0;
877cb5caa98Sdjl 	(void) sigemptyset(&action.sa_mask);
878cb5caa98Sdjl 	(void) sigemptyset(&myset);
879cb5caa98Sdjl 	(void) sigaddset(&myset, SIGHUP);
880cb5caa98Sdjl 
881cb5caa98Sdjl 	if (sigaction(SIGHUP, &action, NULL) < 0) {
882cb5caa98Sdjl 		errnum = errno;
883cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
884cb5caa98Sdjl 		(me, "sigaction (SIGHUP): %s\n", strerror(errnum));
885cb5caa98Sdjl 
886cb5caa98Sdjl 		(void) door_revoke(fd);
887cb5caa98Sdjl 		return (-1);
888cb5caa98Sdjl 	}
889cb5caa98Sdjl 
890cb5caa98Sdjl 	return (fd);
891cb5caa98Sdjl }
892cb5caa98Sdjl 
893cb5caa98Sdjl int
894cb5caa98Sdjl _nscd_setup_child_server(int did)
895cb5caa98Sdjl {
896cb5caa98Sdjl 
897cb5caa98Sdjl 	int		errnum;
898cb5caa98Sdjl 	int		fd;
899cb5caa98Sdjl 	nscd_rc_t	rc;
900cb5caa98Sdjl 	char		*me = "_nscd_setup_child_server";
901cb5caa98Sdjl 
902cb5caa98Sdjl 	/* Re-establish our own server thread pool */
903cb5caa98Sdjl 	(void) door_server_create(server_create);
904cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
905cb5caa98Sdjl 		errnum = errno;
906cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
907cb5caa98Sdjl 		(me, "thr_keycreate failed: %s", strerror(errnum));
908cb5caa98Sdjl 		return (-1);
909cb5caa98Sdjl 	}
910cb5caa98Sdjl 
911cb5caa98Sdjl 	/*
912cb5caa98Sdjl 	 * Create a new door.
913cb5caa98Sdjl 	 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
914cb5caa98Sdjl 	 */
915cb5caa98Sdjl 	(void) close(did);
916cb5caa98Sdjl 	if ((fd = door_create(switcher,
917cb5caa98Sdjl 		NAME_SERVICE_DOOR_COOKIE,
918cb5caa98Sdjl 		DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
919cb5caa98Sdjl 		errnum = errno;
920cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
921cb5caa98Sdjl 		(me, "door_create failed: %s", strerror(errnum));
922cb5caa98Sdjl 		return (-1);
923cb5caa98Sdjl 	}
924cb5caa98Sdjl 
925cb5caa98Sdjl 	/*
926cb5caa98Sdjl 	 * kick off routing socket monitor thread
927cb5caa98Sdjl 	 */
928cb5caa98Sdjl 	if (thr_create(NULL, NULL,
929cb5caa98Sdjl 		(void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
930cb5caa98Sdjl 		errnum = errno;
931cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
932cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
933cb5caa98Sdjl 			strerror(errnum));
934cb5caa98Sdjl 		(void) door_revoke(fd);
935cb5caa98Sdjl 		return (-1);
936cb5caa98Sdjl 	}
937cb5caa98Sdjl 
938cb5caa98Sdjl 	/*
939cb5caa98Sdjl 	 * start monitoring the states of the name service clients
940cb5caa98Sdjl 	 */
941cb5caa98Sdjl 	rc = _nscd_init_smf_monitor();
942cb5caa98Sdjl 	if (rc != NSCD_SUCCESS) {
943cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
944cb5caa98Sdjl 	(me, "unable to start the SMF monitor (rc = %d)\n", rc);
945cb5caa98Sdjl 
946cb5caa98Sdjl 		(void) door_revoke(fd);
947cb5caa98Sdjl 		return (-1);
948cb5caa98Sdjl 	}
949cb5caa98Sdjl 
950cb5caa98Sdjl 	return (fd);
951cb5caa98Sdjl }
952cb5caa98Sdjl 
953cb5caa98Sdjl nscd_rc_t
954cb5caa98Sdjl _nscd_alloc_frontend_cfg()
955cb5caa98Sdjl {
956cb5caa98Sdjl 	frontend_cfg  = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
957cb5caa98Sdjl 	if (frontend_cfg == NULL)
958cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
959cb5caa98Sdjl 
960cb5caa98Sdjl 	return (NSCD_SUCCESS);
961cb5caa98Sdjl }
962cb5caa98Sdjl 
963cb5caa98Sdjl 
964cb5caa98Sdjl /* ARGSUSED */
965cb5caa98Sdjl nscd_rc_t
966cb5caa98Sdjl _nscd_cfg_frontend_notify(
967cb5caa98Sdjl 	void				*data,
968cb5caa98Sdjl 	struct nscd_cfg_param_desc	*pdesc,
969cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
970cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
971cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
972cb5caa98Sdjl 	void				*cookie)
973cb5caa98Sdjl {
974cb5caa98Sdjl 	void				*dp;
975cb5caa98Sdjl 
976cb5caa98Sdjl 	/*
977cb5caa98Sdjl 	 * At init time, the whole group of config params are received.
978cb5caa98Sdjl 	 * At update time, group or individual parameter value could
979cb5caa98Sdjl 	 * be received.
980cb5caa98Sdjl 	 */
981cb5caa98Sdjl 
982cb5caa98Sdjl 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
983cb5caa98Sdjl 		_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
984cb5caa98Sdjl 		/*
985cb5caa98Sdjl 		 * group data is received, copy in the
986cb5caa98Sdjl 		 * entire strcture
987cb5caa98Sdjl 		 */
988cb5caa98Sdjl 		if (_nscd_cfg_flag_is_set(pdesc->pflag,
989cb5caa98Sdjl 			NSCD_CFG_PFLAG_GLOBAL))
990cb5caa98Sdjl 			frontend_cfg_g =
991cb5caa98Sdjl 				*(nscd_cfg_global_frontend_t *)data;
992cb5caa98Sdjl 		else
993cb5caa98Sdjl 			frontend_cfg[nswdb->index] =
994cb5caa98Sdjl 				*(nscd_cfg_frontend_t *)data;
995cb5caa98Sdjl 
996cb5caa98Sdjl 	} else {
997cb5caa98Sdjl 		/*
998cb5caa98Sdjl 		 * individual paramater is received: copy in the
999cb5caa98Sdjl 		 * parameter value.
1000cb5caa98Sdjl 		 */
1001cb5caa98Sdjl 		if (_nscd_cfg_flag_is_set(pdesc->pflag,
1002cb5caa98Sdjl 			NSCD_CFG_PFLAG_GLOBAL))
1003cb5caa98Sdjl 			dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1004cb5caa98Sdjl 		else
1005cb5caa98Sdjl 			dp = (char *)&frontend_cfg[nswdb->index] +
1006cb5caa98Sdjl 				pdesc->p_offset;
1007cb5caa98Sdjl 		(void) memcpy(dp, data, pdesc->p_size);
1008cb5caa98Sdjl 	}
1009cb5caa98Sdjl 
1010cb5caa98Sdjl 	return (NSCD_SUCCESS);
1011cb5caa98Sdjl }
1012cb5caa98Sdjl 
1013cb5caa98Sdjl /* ARGSUSED */
1014cb5caa98Sdjl nscd_rc_t
1015cb5caa98Sdjl _nscd_cfg_frontend_verify(
1016cb5caa98Sdjl 	void				*data,
1017cb5caa98Sdjl 	struct	nscd_cfg_param_desc	*pdesc,
1018cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1019cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
1020cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
1021cb5caa98Sdjl 	void				**cookie)
1022cb5caa98Sdjl {
1023cb5caa98Sdjl 
1024cb5caa98Sdjl 	char				*me = "_nscd_cfg_frontend_verify";
1025cb5caa98Sdjl 
1026cb5caa98Sdjl 	/*
1027cb5caa98Sdjl 	 * if max. number of server threads is set and in effect,
1028cb5caa98Sdjl 	 * don't allow changing of the frontend configuration
1029cb5caa98Sdjl 	 */
1030cb5caa98Sdjl 	if (max_servers_set) {
1031cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1032cb5caa98Sdjl 	(me, "changing of the frontend configuration not allowed now");
1033cb5caa98Sdjl 
1034cb5caa98Sdjl 		return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1035cb5caa98Sdjl 	}
1036cb5caa98Sdjl 
1037cb5caa98Sdjl 	return (NSCD_SUCCESS);
1038cb5caa98Sdjl }
1039cb5caa98Sdjl 
1040cb5caa98Sdjl /* ARGSUSED */
1041cb5caa98Sdjl nscd_rc_t
1042cb5caa98Sdjl _nscd_cfg_frontend_get_stat(
1043cb5caa98Sdjl 	void				**stat,
1044cb5caa98Sdjl 	struct nscd_cfg_stat_desc	*sdesc,
1045cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1046cb5caa98Sdjl 	nscd_cfg_flag_t			*dflag,
1047cb5caa98Sdjl 	void				(**free_stat)(void *stat),
1048cb5caa98Sdjl 	nscd_cfg_error_t		**errorp)
1049cb5caa98Sdjl {
1050cb5caa98Sdjl 	return (NSCD_SUCCESS);
1051cb5caa98Sdjl }
1052cb5caa98Sdjl 
1053cb5caa98Sdjl void
1054cb5caa98Sdjl _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1055cb5caa98Sdjl {
1056cb5caa98Sdjl 	int	i, j;
1057cb5caa98Sdjl 	char	*dbn;
1058cb5caa98Sdjl 
1059cb5caa98Sdjl 	if (max_servers == 0)
1060cb5caa98Sdjl 		max_servers = frontend_cfg_g.common_worker_threads +
1061cb5caa98Sdjl 		frontend_cfg_g.cache_hit_threads;
1062cb5caa98Sdjl 
1063cb5caa98Sdjl 	for (i = 0; i < NSCD_NUM_DB; i++) {
1064cb5caa98Sdjl 
1065cb5caa98Sdjl 		dbn = NSCD_NSW_DB_NAME(i);
1066cb5caa98Sdjl 		if (strcasecmp(dbn, cache_name) == 0) {
1067cb5caa98Sdjl 			j = frontend_cfg[i].worker_thread_per_nsw_db;
1068cb5caa98Sdjl 			(void) sema_init(sema, j, USYNC_THREAD, 0);
1069cb5caa98Sdjl 			max_servers += j;
1070cb5caa98Sdjl 			break;
1071cb5caa98Sdjl 		}
1072cb5caa98Sdjl 	}
1073cb5caa98Sdjl }
1074cb5caa98Sdjl 
1075cb5caa98Sdjl /*
1076cb5caa98Sdjl  * Monitor the routing socket.  Address lists stored in the ipnodes
1077cb5caa98Sdjl  * cache are sorted based on destination address selection rules,
1078cb5caa98Sdjl  * so when things change that could affect that sorting (interfaces
1079cb5caa98Sdjl  * go up or down, flags change, etc.), we clear that cache so the
1080cb5caa98Sdjl  * list will be re-ordered the next time the hostname is resolved.
1081cb5caa98Sdjl  */
1082cb5caa98Sdjl static void
1083cb5caa98Sdjl rts_mon(void)
1084cb5caa98Sdjl {
1085cb5caa98Sdjl 	int	rt_sock, rdlen, idx;
1086cb5caa98Sdjl 	union {
1087cb5caa98Sdjl 		struct {
1088cb5caa98Sdjl 			struct rt_msghdr rtm;
1089cb5caa98Sdjl 			struct sockaddr_storage addrs[RTA_NUMBITS];
1090cb5caa98Sdjl 		} r;
1091cb5caa98Sdjl 		struct if_msghdr ifm;
1092cb5caa98Sdjl 		struct ifa_msghdr ifam;
1093cb5caa98Sdjl 	} mbuf;
1094cb5caa98Sdjl 	struct ifa_msghdr *ifam = &mbuf.ifam;
1095cb5caa98Sdjl 	char	*me = "rts_mon";
1096cb5caa98Sdjl 
1097cb5caa98Sdjl 	rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1098cb5caa98Sdjl 	if (rt_sock < 0) {
1099cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1100cb5caa98Sdjl 		(me, "Failed to open routing socket: %s\n", strerror(errno));
1101cb5caa98Sdjl 		thr_exit(0);
1102cb5caa98Sdjl 	}
1103cb5caa98Sdjl 
1104cb5caa98Sdjl 	for (;;) {
1105cb5caa98Sdjl 		rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1106cb5caa98Sdjl 		if (rdlen <= 0) {
1107cb5caa98Sdjl 			if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1108cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1109cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1110cb5caa98Sdjl 				(me, "routing socket read: %s\n",
1111cb5caa98Sdjl 					strerror(errno));
1112cb5caa98Sdjl 				thr_exit(0);
1113cb5caa98Sdjl 			}
1114cb5caa98Sdjl 			continue;
1115cb5caa98Sdjl 		}
1116cb5caa98Sdjl 		if (ifam->ifam_version != RTM_VERSION) {
1117cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1118cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1119cb5caa98Sdjl 				(me, "rx unknown version (%d) on "
1120cb5caa98Sdjl 					"routing socket.\n",
1121cb5caa98Sdjl 					ifam->ifam_version);
1122cb5caa98Sdjl 			continue;
1123cb5caa98Sdjl 		}
1124cb5caa98Sdjl 		switch (ifam->ifam_type) {
1125cb5caa98Sdjl 		case RTM_NEWADDR:
1126cb5caa98Sdjl 		case RTM_DELADDR:
1127cb5caa98Sdjl 			/* if no ipnodes cache, then nothing to do */
1128cb5caa98Sdjl 			idx = get_cache_idx("ipnodes");
1129cb5caa98Sdjl 			if (cache_ctx_p[idx] == NULL ||
1130cb5caa98Sdjl 				cache_ctx_p[idx]->reaper_on != nscd_true)
1131cb5caa98Sdjl 				break;
1132cb5caa98Sdjl 			nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1133cb5caa98Sdjl 			break;
1134cb5caa98Sdjl 		case RTM_ADD:
1135cb5caa98Sdjl 		case RTM_DELETE:
1136cb5caa98Sdjl 		case RTM_CHANGE:
1137cb5caa98Sdjl 		case RTM_GET:
1138cb5caa98Sdjl 		case RTM_LOSING:
1139cb5caa98Sdjl 		case RTM_REDIRECT:
1140cb5caa98Sdjl 		case RTM_MISS:
1141cb5caa98Sdjl 		case RTM_LOCK:
1142cb5caa98Sdjl 		case RTM_OLDADD:
1143cb5caa98Sdjl 		case RTM_OLDDEL:
1144cb5caa98Sdjl 		case RTM_RESOLVE:
1145cb5caa98Sdjl 		case RTM_IFINFO:
1146cb5caa98Sdjl 			break;
1147cb5caa98Sdjl 		default:
1148cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1149cb5caa98Sdjl 			(me, "rx unknown msg type (%d) on routing socket.\n",
1150cb5caa98Sdjl 			    ifam->ifam_type);
1151cb5caa98Sdjl 			break;
1152cb5caa98Sdjl 		}
1153cb5caa98Sdjl 	}
1154cb5caa98Sdjl }
1155cb5caa98Sdjl 
1156cb5caa98Sdjl static void
1157cb5caa98Sdjl keep_open_dns_socket(void)
1158cb5caa98Sdjl {
1159cb5caa98Sdjl 	_res.options |= RES_STAYOPEN; /* just keep this udp socket open */
1160cb5caa98Sdjl }
1161