xref: /titanic_44/usr/src/cmd/nscd/nscd_frontend.c (revision 606f6aa3d37f0f8e8282e483c1400bae5275aeeb)
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*606f6aa3Smichen  * Copyright 2007 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 
329e37190e5Smichen void
330e37190e5Smichen _nscd_APP_check_cred(
331cb5caa98Sdjl 	void		*buf,
332cb5caa98Sdjl 	pid_t		*pidp,
333e37190e5Smichen 	char		*dc_str,
334e37190e5Smichen 	int		log_comp,
335e37190e5Smichen 	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;
341e37190e5Smichen 	pid_t		pid;
342cb5caa98Sdjl 	int		errnum;
343e37190e5Smichen 	char		*me = "_nscd_APP_check_cred";
344cb5caa98Sdjl 
345cb5caa98Sdjl 	if (door_ucred(&uc) != 0) {
346cb5caa98Sdjl 		errnum = errno;
347e37190e5Smichen 		_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 
353e37190e5Smichen 	NSCD_SET_STATUS_SUCCESS(phdr);
354e37190e5Smichen 	pid = ucred_getpid(uc);
355cb5caa98Sdjl 	if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
356cb5caa98Sdjl 		euid = ucred_geteuid(uc))) {
357e37190e5Smichen 		if (pidp != NULL) {
358e37190e5Smichen 			if (*pidp == (pid_t)-1)
359e37190e5Smichen 				*pidp = pid;
360e37190e5Smichen 			else if (*pidp != pid) {
361e37190e5Smichen 				NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
362e37190e5Smichen 			}
363e37190e5Smichen 		}
364e37190e5Smichen 	} else {
365e37190e5Smichen 		NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
366cb5caa98Sdjl 	}
367cb5caa98Sdjl 
368cb5caa98Sdjl 	ucred_free(uc);
369cb5caa98Sdjl 
370e37190e5Smichen 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
371e37190e5Smichen 		_NSCD_LOG(log_comp, log_level)
372e37190e5Smichen 		(me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
373e37190e5Smichen 		"euid %d, header ruid %d, header euid %d\n", dc_str,
374e37190e5Smichen 		pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
375e37190e5Smichen 		((nss_pheader_t *)(buf))->p_ruid,
376e37190e5Smichen 		((nss_pheader_t *)(buf))->p_euid);
377e37190e5Smichen 	}
378cb5caa98Sdjl }
379cb5caa98Sdjl 
380*606f6aa3Smichen /* log error and return -1 when an invalid packed buffer header is found */
381*606f6aa3Smichen static int
382*606f6aa3Smichen pheader_error(nss_pheader_t *phdr, uint32_t call_number)
383*606f6aa3Smichen {
384*606f6aa3Smichen 	char *call_num_str;
385*606f6aa3Smichen 
386*606f6aa3Smichen 	switch (call_number) {
387*606f6aa3Smichen 	case NSCD_SEARCH:
388*606f6aa3Smichen 		call_num_str = "NSCD_SEARCH";
389*606f6aa3Smichen 		break;
390*606f6aa3Smichen 	case NSCD_SETENT:
391*606f6aa3Smichen 		call_num_str = "NSCD_SETENT";
392*606f6aa3Smichen 		break;
393*606f6aa3Smichen 	case NSCD_GETENT:
394*606f6aa3Smichen 		call_num_str = "NSCD_GETENT";
395*606f6aa3Smichen 		break;
396*606f6aa3Smichen 	case NSCD_ENDENT:
397*606f6aa3Smichen 		call_num_str = "NSCD_ENDENT";
398*606f6aa3Smichen 		break;
399*606f6aa3Smichen 	case NSCD_PUT:
400*606f6aa3Smichen 		call_num_str = "NSCD_PUT";
401*606f6aa3Smichen 		break;
402*606f6aa3Smichen 	case NSCD_GETHINTS:
403*606f6aa3Smichen 		call_num_str = "NSCD_GETHINTS";
404*606f6aa3Smichen 		break;
405*606f6aa3Smichen 	default:
406*606f6aa3Smichen 		call_num_str = "UNKNOWN";
407*606f6aa3Smichen 		break;
408*606f6aa3Smichen 	}
409*606f6aa3Smichen 
410*606f6aa3Smichen 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
411*606f6aa3Smichen 	("pheader_error", "call number %s: invalid packed buffer header\n",
412*606f6aa3Smichen 		call_num_str);
413*606f6aa3Smichen 
414*606f6aa3Smichen 	NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
415*606f6aa3Smichen 	return (-1);
416*606f6aa3Smichen }
417*606f6aa3Smichen 
418*606f6aa3Smichen /*
419*606f6aa3Smichen  * Validate the header of a getXbyY or setent/getent/endent request.
420*606f6aa3Smichen  * Return 0 if good, -1 otherwise.
421*606f6aa3Smichen  *
422*606f6aa3Smichen  * A valid header looks like the following (size is arg_size, does
423*606f6aa3Smichen  * not include the output area):
424*606f6aa3Smichen  * +----------------------------------+ --
425*606f6aa3Smichen  * | nss_pheader_t (header fixed part)| ^
426*606f6aa3Smichen  * |                                  | |
427*606f6aa3Smichen  * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
428*606f6aa3Smichen  * | data_off ....                    | |
429*606f6aa3Smichen  * |                                  | v
430*606f6aa3Smichen  * +----------------------------------+ <----- dbd_off
431*606f6aa3Smichen  * | dbd (database description)       | ^
432*606f6aa3Smichen  * | nss_dbd_t + up to 3 strings      | |
433*606f6aa3Smichen  * | length = sizeof(nss_dbd_t) +     | len = key_off - dbd_off
434*606f6aa3Smichen  * |          length of 3 strings +   | |
435*606f6aa3Smichen  * |          length of padding       | |
436*606f6aa3Smichen  * | (total length in multiple of 4)  | v
437*606f6aa3Smichen  * +----------------------------------+ <----- key_off
438*606f6aa3Smichen  * | lookup key                       | ^
439*606f6aa3Smichen  * | nss_XbyY_key_t, content varies,  | |
440*606f6aa3Smichen  * | based on database and lookup op  | len = data_off - key_off
441*606f6aa3Smichen  * | length = data_off - key_off      | |
442*606f6aa3Smichen  * | including padding, multiple of 4 | v
443*606f6aa3Smichen  * +----------------------------------+ <----- data_off (= arg_size)
444*606f6aa3Smichen  * |                                  | ^
445*606f6aa3Smichen  * | area to hold results             | |
446*606f6aa3Smichen  * |                                  | len = data_len (= pbufsiz -
447*606f6aa3Smichen  * |                                  | |                 data_off)
448*606f6aa3Smichen  * |                                  | v
449*606f6aa3Smichen  * +----------------------------------+ <----- pbufsiz
450*606f6aa3Smichen  */
451*606f6aa3Smichen static int
452*606f6aa3Smichen validate_pheader(
453*606f6aa3Smichen 	void		*argp,
454*606f6aa3Smichen 	size_t		arg_size,
455*606f6aa3Smichen 	uint32_t	call_number)
456*606f6aa3Smichen {
457*606f6aa3Smichen 	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
458*606f6aa3Smichen 	nssuint_t	l1, l2;
459*606f6aa3Smichen 
460*606f6aa3Smichen 	/*
461*606f6aa3Smichen 	 * current version is NSCD_HEADER_REV, length of the fixed part
462*606f6aa3Smichen 	 * of the header must match the size of nss_pheader_t
463*606f6aa3Smichen 	 */
464*606f6aa3Smichen 	if (phdr->p_version != NSCD_HEADER_REV ||
465*606f6aa3Smichen 			phdr->dbd_off != sizeof (nss_pheader_t))
466*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
467*606f6aa3Smichen 
468*606f6aa3Smichen 	/*
469*606f6aa3Smichen 	 * buffer size and offsets must be in multiple of 4
470*606f6aa3Smichen 	 */
471*606f6aa3Smichen 	if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
472*606f6aa3Smichen 		(phdr->data_off & 3))
473*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
474*606f6aa3Smichen 
475*606f6aa3Smichen 	/*
476*606f6aa3Smichen 	 * the input arg_size is the length of the request header
477*606f6aa3Smichen 	 * and should be less than NSCD_PHDR_MAXLEN
478*606f6aa3Smichen 	 */
479*606f6aa3Smichen 	if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
480*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
481*606f6aa3Smichen 
482*606f6aa3Smichen 	/* get length of the dbd area */
483*606f6aa3Smichen 	l1 = phdr->key_off - phdr-> dbd_off;
484*606f6aa3Smichen 
485*606f6aa3Smichen 	/*
486*606f6aa3Smichen 	 * dbd area may contain padding, so length of dbd should
487*606f6aa3Smichen 	 * not be less than the length of the actual data
488*606f6aa3Smichen 	 */
489*606f6aa3Smichen 	if (l1 < phdr->dbd_len)
490*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
491*606f6aa3Smichen 
492*606f6aa3Smichen 	/* get length of the key area */
493*606f6aa3Smichen 	l2 = phdr->data_off - phdr->key_off;
494*606f6aa3Smichen 
495*606f6aa3Smichen 	/*
496*606f6aa3Smichen 	 * key area may contain padding, so length of key area should
497*606f6aa3Smichen 	 * not be less than the length of the actual data
498*606f6aa3Smichen 	 */
499*606f6aa3Smichen 	if (l2 < phdr->key_len)
500*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
501*606f6aa3Smichen 
502*606f6aa3Smichen 	/*
503*606f6aa3Smichen 	 * length of fixed part + lengths of dbd and key area = length of
504*606f6aa3Smichen 	 * the request header
505*606f6aa3Smichen 	 */
506*606f6aa3Smichen 	if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
507*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
508*606f6aa3Smichen 
509*606f6aa3Smichen 	/* header length + data length = buffer length */
510*606f6aa3Smichen 	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
511*606f6aa3Smichen 		return (pheader_error(phdr, call_number));
512*606f6aa3Smichen 
513*606f6aa3Smichen 	return (0);
514*606f6aa3Smichen }
515*606f6aa3Smichen 
516*606f6aa3Smichen /* log error and return -1 when an invalid nscd to nscd buffer is found */
517*606f6aa3Smichen static int
518*606f6aa3Smichen N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
519*606f6aa3Smichen {
520*606f6aa3Smichen 	char *call_num_str;
521*606f6aa3Smichen 
522*606f6aa3Smichen 	switch (call_number) {
523*606f6aa3Smichen 	case NSCD_PING:
524*606f6aa3Smichen 		call_num_str = "NSCD_PING";
525*606f6aa3Smichen 		break;
526*606f6aa3Smichen 
527*606f6aa3Smichen 	case NSCD_IMHERE:
528*606f6aa3Smichen 		call_num_str = "NSCD_IMHERE";
529*606f6aa3Smichen 		break;
530*606f6aa3Smichen 
531*606f6aa3Smichen 	case NSCD_PULSE:
532*606f6aa3Smichen 		call_num_str = "NSCD_PULSE";
533*606f6aa3Smichen 		break;
534*606f6aa3Smichen 
535*606f6aa3Smichen 	case NSCD_FORK:
536*606f6aa3Smichen 		call_num_str = "NSCD_FORK";
537*606f6aa3Smichen 		break;
538*606f6aa3Smichen 
539*606f6aa3Smichen 	case NSCD_KILL:
540*606f6aa3Smichen 		call_num_str = "NSCD_KILL";
541*606f6aa3Smichen 		break;
542*606f6aa3Smichen 
543*606f6aa3Smichen 	case NSCD_REFRESH:
544*606f6aa3Smichen 		call_num_str = "NSCD_REFRESH";
545*606f6aa3Smichen 		break;
546*606f6aa3Smichen 
547*606f6aa3Smichen 	case NSCD_GETPUADMIN:
548*606f6aa3Smichen 		call_num_str = "NSCD_GETPUADMIN";
549*606f6aa3Smichen 		break;
550*606f6aa3Smichen 
551*606f6aa3Smichen 	case NSCD_GETADMIN:
552*606f6aa3Smichen 		call_num_str = "NSCD_GETADMIN";
553*606f6aa3Smichen 		break;
554*606f6aa3Smichen 
555*606f6aa3Smichen 	case NSCD_SETADMIN:
556*606f6aa3Smichen 		call_num_str = "NSCD_SETADMIN";
557*606f6aa3Smichen 		break;
558*606f6aa3Smichen 
559*606f6aa3Smichen 	case NSCD_KILLSERVER:
560*606f6aa3Smichen 		call_num_str = "NSCD_KILLSERVER";
561*606f6aa3Smichen 		break;
562*606f6aa3Smichen 	default:
563*606f6aa3Smichen 		call_num_str = "UNKNOWN";
564*606f6aa3Smichen 		break;
565*606f6aa3Smichen 	}
566*606f6aa3Smichen 
567*606f6aa3Smichen 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
568*606f6aa3Smichen 	("N2Nbuf_error", "call number %s: invalid N2N buffer\n",
569*606f6aa3Smichen 		call_num_str);
570*606f6aa3Smichen 
571*606f6aa3Smichen 	NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
572*606f6aa3Smichen 			NSCD_DOOR_BUFFER_CHECK_FAILED);
573*606f6aa3Smichen 
574*606f6aa3Smichen 	return (-1);
575*606f6aa3Smichen }
576*606f6aa3Smichen 
577*606f6aa3Smichen /*
578*606f6aa3Smichen  * Validate the buffer of an nscd to nscd request.
579*606f6aa3Smichen  * Return 0 if good, -1 otherwise.
580*606f6aa3Smichen  *
581*606f6aa3Smichen  * A valid buffer looks like the following (size is arg_size):
582*606f6aa3Smichen  * +----------------------------------+ --
583*606f6aa3Smichen  * | nss_pheader_t (header fixed part)| ^
584*606f6aa3Smichen  * |                                  | |
585*606f6aa3Smichen  * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
586*606f6aa3Smichen  * | data_off ....                    | |
587*606f6aa3Smichen  * |                                  | v
588*606f6aa3Smichen  * +----------------------------------+ <---dbd_off = key_off = data_off
589*606f6aa3Smichen  * |                                  | ^
590*606f6aa3Smichen  * | input data/output data           | |
591*606f6aa3Smichen  * | OR no data                       | len = data_len (= pbufsiz -
592*606f6aa3Smichen  * |                                  | |                 data_off)
593*606f6aa3Smichen  * |                                  | | len could be zero
594*606f6aa3Smichen  * |                                  | v
595*606f6aa3Smichen  * +----------------------------------+ <--- pbufsiz
596*606f6aa3Smichen  */
597*606f6aa3Smichen static int
598*606f6aa3Smichen validate_N2Nbuf(
599*606f6aa3Smichen 	void		*argp,
600*606f6aa3Smichen 	size_t		arg_size,
601*606f6aa3Smichen 	uint32_t	call_number)
602*606f6aa3Smichen {
603*606f6aa3Smichen 	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
604*606f6aa3Smichen 
605*606f6aa3Smichen 	/*
606*606f6aa3Smichen 	 * current version is NSCD_HEADER_REV, length of the fixed part
607*606f6aa3Smichen 	 * of the header must match the size of nss_pheader_t
608*606f6aa3Smichen 	 */
609*606f6aa3Smichen 	if (phdr->p_version != NSCD_HEADER_REV ||
610*606f6aa3Smichen 			phdr->dbd_off != sizeof (nss_pheader_t))
611*606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
612*606f6aa3Smichen 
613*606f6aa3Smichen 	/*
614*606f6aa3Smichen 	 * There are no dbd and key data, so the dbd, key, data
615*606f6aa3Smichen 	 * offsets should be equal
616*606f6aa3Smichen 	 */
617*606f6aa3Smichen 	if (phdr->dbd_off != phdr->key_off ||
618*606f6aa3Smichen 		phdr->dbd_off != phdr->data_off)
619*606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
620*606f6aa3Smichen 
621*606f6aa3Smichen 	/*
622*606f6aa3Smichen 	 * the input arg_size is the buffer length and should
623*606f6aa3Smichen 	 * be less or equal than NSCD_N2NBUF_MAXLEN
624*606f6aa3Smichen 	 */
625*606f6aa3Smichen 	if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
626*606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
627*606f6aa3Smichen 
628*606f6aa3Smichen 	/* header length + data length = buffer length */
629*606f6aa3Smichen 	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
630*606f6aa3Smichen 		return (N2Nbuf_error(phdr, call_number));
631*606f6aa3Smichen 
632*606f6aa3Smichen 	return (0);
633*606f6aa3Smichen }
634*606f6aa3Smichen 
635cb5caa98Sdjl static void
636cb5caa98Sdjl lookup(char *argp, size_t arg_size)
637cb5caa98Sdjl {
638cb5caa98Sdjl 	nsc_lookup_args_t	largs;
639cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
640cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
641cb5caa98Sdjl 
642cb5caa98Sdjl 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
643cb5caa98Sdjl 		sizeof (space));
644cb5caa98Sdjl 
645*606f6aa3Smichen 	/*
646*606f6aa3Smichen 	 * make sure the first couple bytes of the data area is null,
647*606f6aa3Smichen 	 * so that bad strings in the packed header stop here
648*606f6aa3Smichen 	 */
649*606f6aa3Smichen 	(void) memset((char *)phdr + phdr->data_off, 0, 16);
650*606f6aa3Smichen 
651cb5caa98Sdjl 	(void) memset(&largs, 0, sizeof (largs));
652cb5caa98Sdjl 	largs.buffer = argp;
653cb5caa98Sdjl 	largs.bufsize = arg_size;
654cb5caa98Sdjl 	nsc_lookup(&largs, 0);
655cb5caa98Sdjl 
656cb5caa98Sdjl 	/*
657cb5caa98Sdjl 	 * only the PUN needs to keep track of the
658cb5caa98Sdjl 	 * activity count to determine when to
659cb5caa98Sdjl 	 * terminate itself
660cb5caa98Sdjl 	 */
661cb5caa98Sdjl 	if (_whoami == NSCD_CHILD) {
662cb5caa98Sdjl 		(void) mutex_lock(&activity_lock);
663cb5caa98Sdjl 		++activity;
664cb5caa98Sdjl 		(void) mutex_unlock(&activity_lock);
665cb5caa98Sdjl 	}
666cb5caa98Sdjl 
667cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
668cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
669cb5caa98Sdjl }
670cb5caa98Sdjl 
671cb5caa98Sdjl static void
672cb5caa98Sdjl getent(char *argp, size_t arg_size)
673cb5caa98Sdjl {
674cb5caa98Sdjl 	char			space[NSCD_LOOKUP_BUFSIZE];
675cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)(void *)argp;
676cb5caa98Sdjl 
677cb5caa98Sdjl 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr,
678cb5caa98Sdjl 		space, sizeof (space));
679cb5caa98Sdjl 
680cb5caa98Sdjl 	nss_pgetent(argp, arg_size);
681cb5caa98Sdjl 
682cb5caa98Sdjl 	NSCD_SET_RETURN_ARG(phdr, arg_size);
683cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
684cb5caa98Sdjl }
685cb5caa98Sdjl 
686cb5caa98Sdjl static int
687cb5caa98Sdjl is_db_per_user(void *buf, char *dblist)
688cb5caa98Sdjl {
689cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
690cb5caa98Sdjl 	nss_dbd_t	*pdbd;
691cb5caa98Sdjl 	char		*dbname, *dbn;
692cb5caa98Sdjl 	int		len;
693cb5caa98Sdjl 
694cb5caa98Sdjl 	/* copy db name into a temp buffer */
695cb5caa98Sdjl 	pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
696cb5caa98Sdjl 	dbname = (char *)pdbd + pdbd->o_name;
697cb5caa98Sdjl 	len = strlen(dbname);
698cb5caa98Sdjl 	dbn = alloca(len + 2);
699cb5caa98Sdjl 	(void) memcpy(dbn, dbname, len);
700cb5caa98Sdjl 
701cb5caa98Sdjl 	/* check if <dbname> + ',' can be found in the dblist string */
702cb5caa98Sdjl 	dbn[len] = ',';
703cb5caa98Sdjl 	dbn[len + 1] = '\0';
704cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
705cb5caa98Sdjl 		return (1);
706cb5caa98Sdjl 
707cb5caa98Sdjl 	/*
708cb5caa98Sdjl 	 * check if <dbname> can be found in the last part
709cb5caa98Sdjl 	 * of the dblist string
710cb5caa98Sdjl 	 */
711cb5caa98Sdjl 	dbn[len] = '\0';
712cb5caa98Sdjl 	if (strstr(dblist, dbn) != NULL)
713cb5caa98Sdjl 		return (1);
714cb5caa98Sdjl 
715cb5caa98Sdjl 	return (0);
716cb5caa98Sdjl }
717cb5caa98Sdjl 
718cb5caa98Sdjl /*
719cb5caa98Sdjl  * Check to see if all conditions are met for processing per-user
720cb5caa98Sdjl  * requests. Returns 1 if yes, -1 if backend is not configured,
721cb5caa98Sdjl  * 0 otherwise.
722cb5caa98Sdjl  */
723cb5caa98Sdjl static int
724cb5caa98Sdjl need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
725cb5caa98Sdjl {
726cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
727cb5caa98Sdjl 
728cb5caa98Sdjl 	NSCD_SET_STATUS_SUCCESS(phdr);
729cb5caa98Sdjl 
730cb5caa98Sdjl 	/* if already a per-user nscd, no need to get per-user door */
731cb5caa98Sdjl 	if (whoami == NSCD_CHILD)
732cb5caa98Sdjl 		return (0);
733cb5caa98Sdjl 
734cb5caa98Sdjl 	/* forker shouldn't be asked */
735cb5caa98Sdjl 	if (whoami == NSCD_FORKER) {
736cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
737cb5caa98Sdjl 		return (0);
738cb5caa98Sdjl 	}
739cb5caa98Sdjl 
740cb5caa98Sdjl 	/* if door client is root, no need for a per-user door */
741cb5caa98Sdjl 	if (uid == 0)
742cb5caa98Sdjl 		return (0);
743cb5caa98Sdjl 
744cb5caa98Sdjl 	/*
745cb5caa98Sdjl 	 * if per-user lookup is not configured, no per-user
746cb5caa98Sdjl 	 * door available
747cb5caa98Sdjl 	 */
748cb5caa98Sdjl 	if (_nscd_is_self_cred_on(0, dblist) == 0)
749cb5caa98Sdjl 		return (-1);
750cb5caa98Sdjl 
751cb5caa98Sdjl 	/*
752cb5caa98Sdjl 	 * if per-user lookup is not configured for the db,
753cb5caa98Sdjl 	 * don't bother
754cb5caa98Sdjl 	 */
755cb5caa98Sdjl 	if (is_db_per_user(phdr, *dblist) == 0)
756cb5caa98Sdjl 		return (0);
757cb5caa98Sdjl 
758cb5caa98Sdjl 	return (1);
759cb5caa98Sdjl }
760cb5caa98Sdjl 
761cb5caa98Sdjl static void
762cb5caa98Sdjl if_selfcred_return_per_user_door(char *argp, size_t arg_size,
763cb5caa98Sdjl 	door_desc_t *dp, int whoami)
764cb5caa98Sdjl {
765cb5caa98Sdjl 	nss_pheader_t	*phdr = (nss_pheader_t *)((void *)argp);
766cb5caa98Sdjl 	char		*dblist;
767cb5caa98Sdjl 	int		door = -1;
768cb5caa98Sdjl 	int		rc = 0;
769cb5caa98Sdjl 	door_desc_t	desc;
770*606f6aa3Smichen 	char		*space;
771*606f6aa3Smichen 	int		len;
772cb5caa98Sdjl 
773cb5caa98Sdjl 	/*
774cb5caa98Sdjl 	 * check to see if self-cred is configured and
775cb5caa98Sdjl 	 * need to return an alternate PUN door
776cb5caa98Sdjl 	 */
777cb5caa98Sdjl 	if (per_user_is_on == 1) {
778cb5caa98Sdjl 		rc = need_per_user_door(argp, whoami,
779cb5caa98Sdjl 			_nscd_get_client_euid(), &dblist);
780cb5caa98Sdjl 		if (rc == -1)
781cb5caa98Sdjl 			per_user_is_on = 0;
782cb5caa98Sdjl 	}
783cb5caa98Sdjl 	if (rc <= 0) {
784cb5caa98Sdjl 		/*
785cb5caa98Sdjl 		 * self-cred not configured, and no error detected,
786cb5caa98Sdjl 		 * return to continue the door call processing
787cb5caa98Sdjl 		 */
788cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
789cb5caa98Sdjl 			return;
790cb5caa98Sdjl 		else
791cb5caa98Sdjl 			/*
792cb5caa98Sdjl 			 * configured but error detected,
793cb5caa98Sdjl 			 * stop the door call processing
794cb5caa98Sdjl 			 */
795cb5caa98Sdjl 			(void) door_return(argp, phdr->data_off, NULL, 0);
796cb5caa98Sdjl 	}
797cb5caa98Sdjl 
798cb5caa98Sdjl 	/* get the alternate PUN door */
799cb5caa98Sdjl 	_nscd_proc_alt_get(argp, &door);
800cb5caa98Sdjl 	if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
801cb5caa98Sdjl 		(void) door_return(argp, phdr->data_off, NULL, 0);
802cb5caa98Sdjl 	}
803cb5caa98Sdjl 
804cb5caa98Sdjl 	/* return the alternate door descriptor */
805*606f6aa3Smichen 	len = strlen(dblist) + 1;
806*606f6aa3Smichen 	space = alloca(arg_size + len);
807*606f6aa3Smichen 	phdr->data_len = len;
808*606f6aa3Smichen 	(void) memcpy(space, phdr, arg_size);
809*606f6aa3Smichen 	(void) strncpy((char *)space + arg_size, dblist, len);
810cb5caa98Sdjl 	dp = &desc;
811cb5caa98Sdjl 	dp->d_attributes = DOOR_DESCRIPTOR;
812cb5caa98Sdjl 	dp->d_data.d_desc.d_descriptor = door;
813*606f6aa3Smichen 	arg_size += len;
814*606f6aa3Smichen 	(void) door_return(space, arg_size, dp, 1);
815cb5caa98Sdjl }
816cb5caa98Sdjl 
817cb5caa98Sdjl /*ARGSUSED*/
818cb5caa98Sdjl static void
819cb5caa98Sdjl switcher(void *cookie, char *argp, size_t arg_size,
820cb5caa98Sdjl     door_desc_t *dp, uint_t n_desc)
821cb5caa98Sdjl {
822cb5caa98Sdjl 	int			iam;
823cb5caa98Sdjl 	pid_t			ent_pid = -1;
824cb5caa98Sdjl 	nss_pheader_t		*phdr = (nss_pheader_t *)((void *)argp);
825cb5caa98Sdjl 	void			*uptr;
826*606f6aa3Smichen 	int			len;
827*606f6aa3Smichen 	size_t			buflen;
828cb5caa98Sdjl 	int			callnum;
829cb5caa98Sdjl 	char			*me = "switcher";
830cb5caa98Sdjl 
831cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
832cb5caa98Sdjl 	(me, "switcher ...\n");
833cb5caa98Sdjl 
834cb5caa98Sdjl 	if (argp == DOOR_UNREF_DATA) {
835cb5caa98Sdjl 		(void) printf("Door Slam... exiting\n");
836cb5caa98Sdjl 		exit(0);
837cb5caa98Sdjl 	}
838cb5caa98Sdjl 
839cb5caa98Sdjl 	if (argp == NULL) { /* empty door call */
840cb5caa98Sdjl 		(void) door_return(NULL, 0, 0, 0); /* return the favor */
841cb5caa98Sdjl 	}
842cb5caa98Sdjl 
843cb5caa98Sdjl 	/*
844cb5caa98Sdjl 	 *  need to restart if main nscd and config file(s) changed
845cb5caa98Sdjl 	 */
846cb5caa98Sdjl 	if (_whoami == NSCD_MAIN)
847cb5caa98Sdjl 		restart_if_cfgfile_changed();
848cb5caa98Sdjl 
849cb5caa98Sdjl 	if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
850*606f6aa3Smichen 
851*606f6aa3Smichen 		/* make sure the packed buffer header is good */
852*606f6aa3Smichen 		if (validate_pheader(argp, arg_size,
853*606f6aa3Smichen 				phdr->nsc_callnumber) == -1)
854*606f6aa3Smichen 			(void) door_return(argp, arg_size, NULL, 0);
855*606f6aa3Smichen 
856cb5caa98Sdjl 		switch (phdr->nsc_callnumber) {
857*606f6aa3Smichen 
858cb5caa98Sdjl 		case NSCD_SEARCH:
859cb5caa98Sdjl 
860cb5caa98Sdjl 		/* if a fallback to main nscd, skip per-user setup */
861cb5caa98Sdjl 		if (phdr->p_status != NSS_ALTRETRY)
862cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
863cb5caa98Sdjl 				dp, _whoami);
864cb5caa98Sdjl 		lookup(argp, arg_size);
865cb5caa98Sdjl 
866cb5caa98Sdjl 		break;
867cb5caa98Sdjl 
868cb5caa98Sdjl 		case NSCD_SETENT:
869cb5caa98Sdjl 
870e37190e5Smichen 		_nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
871e37190e5Smichen 			NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
872cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
873cb5caa98Sdjl 			if_selfcred_return_per_user_door(argp, arg_size,
874cb5caa98Sdjl 				dp, _whoami);
875cb5caa98Sdjl 			nss_psetent(argp, arg_size, ent_pid);
876cb5caa98Sdjl 		}
877cb5caa98Sdjl 		break;
878cb5caa98Sdjl 
879cb5caa98Sdjl 		case NSCD_GETENT:
880cb5caa98Sdjl 
881cb5caa98Sdjl 		getent(argp, arg_size);
882cb5caa98Sdjl 		break;
883cb5caa98Sdjl 
884cb5caa98Sdjl 		case NSCD_ENDENT:
885cb5caa98Sdjl 
886cb5caa98Sdjl 		nss_pendent(argp, arg_size);
887cb5caa98Sdjl 		break;
888cb5caa98Sdjl 
889cb5caa98Sdjl 		case NSCD_PUT:
890cb5caa98Sdjl 
891cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
892cb5caa98Sdjl 		(me, "door call NSCD_PUT not supported yet\n");
893cb5caa98Sdjl 
894cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
895cb5caa98Sdjl 		break;
896cb5caa98Sdjl 
897cb5caa98Sdjl 		case NSCD_GETHINTS:
898cb5caa98Sdjl 
899cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
900cb5caa98Sdjl 		(me, "door call NSCD_GETHINTS not supported yet\n");
901cb5caa98Sdjl 
902cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
903cb5caa98Sdjl 		break;
904cb5caa98Sdjl 
905cb5caa98Sdjl 		default:
906cb5caa98Sdjl 
907cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
908cb5caa98Sdjl 		(me, "Unknown name service door call op %x\n",
909cb5caa98Sdjl 		phdr->nsc_callnumber);
910cb5caa98Sdjl 
911cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
912cb5caa98Sdjl 		break;
913cb5caa98Sdjl 		}
914cb5caa98Sdjl 
915cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
916cb5caa98Sdjl 	}
917cb5caa98Sdjl 
918cb5caa98Sdjl 	iam = NSCD_MAIN;
919cb5caa98Sdjl 	callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
920cb5caa98Sdjl 	if (callnum == NSCD_IMHERE ||
921cb5caa98Sdjl 		callnum == NSCD_PULSE || callnum == NSCD_FORK)
922cb5caa98Sdjl 		iam = phdr->nsc_callnumber & NSCD_WHOAMI;
923cb5caa98Sdjl 	else
924cb5caa98Sdjl 		callnum = phdr->nsc_callnumber;
925cb5caa98Sdjl 
926cb5caa98Sdjl 	/* nscd -> nscd v2 calls */
927*606f6aa3Smichen 
928*606f6aa3Smichen 	/* make sure the buffer is good */
929*606f6aa3Smichen 	if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
930*606f6aa3Smichen 		(void) door_return(argp, arg_size, NULL, 0);
931*606f6aa3Smichen 
932cb5caa98Sdjl 	switch (callnum) {
933cb5caa98Sdjl 
934cb5caa98Sdjl 	case NSCD_PING:
935cb5caa98Sdjl 		NSCD_SET_STATUS_SUCCESS(phdr);
936cb5caa98Sdjl 		break;
937cb5caa98Sdjl 
938cb5caa98Sdjl 	case NSCD_IMHERE:
939cb5caa98Sdjl 		_nscd_proc_iamhere(argp, dp, n_desc, iam);
940cb5caa98Sdjl 		break;
941cb5caa98Sdjl 
942cb5caa98Sdjl 	case NSCD_PULSE:
943cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_PULSE");
944cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
945cb5caa98Sdjl 			_nscd_proc_pulse(argp, iam);
946cb5caa98Sdjl 		break;
947cb5caa98Sdjl 
948cb5caa98Sdjl 	case NSCD_FORK:
949cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_FORK");
950cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
951cb5caa98Sdjl 			_nscd_proc_fork(argp, iam);
952cb5caa98Sdjl 		break;
953cb5caa98Sdjl 
954cb5caa98Sdjl 	case NSCD_KILL:
955cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILL");
956cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
957cb5caa98Sdjl 			exit(0);
958cb5caa98Sdjl 		break;
959cb5caa98Sdjl 
960cb5caa98Sdjl 	case NSCD_REFRESH:
961*606f6aa3Smichen 		N2N_check_priv(argp, "NSCD_REFRESH");
962*606f6aa3Smichen 		if (NSCD_STATUS_IS_OK(phdr)) {
963cb5caa98Sdjl 			if (_nscd_refresh() != NSCD_SUCCESS)
964cb5caa98Sdjl 				exit(1);
965cb5caa98Sdjl 			NSCD_SET_STATUS_SUCCESS(phdr);
966*606f6aa3Smichen 		}
967cb5caa98Sdjl 		break;
968cb5caa98Sdjl 
969cb5caa98Sdjl 	case NSCD_GETPUADMIN:
970cb5caa98Sdjl 
971cb5caa98Sdjl 		if (_nscd_is_self_cred_on(0, NULL)) {
972cb5caa98Sdjl 			_nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
973cb5caa98Sdjl 		} else {
974cb5caa98Sdjl 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
975cb5caa98Sdjl 				NSCD_SELF_CRED_NOT_CONFIGURED);
976cb5caa98Sdjl 		}
977cb5caa98Sdjl 		break;
978cb5caa98Sdjl 
979cb5caa98Sdjl 	case NSCD_GETADMIN:
980cb5caa98Sdjl 
981cb5caa98Sdjl 		len = _nscd_door_getadmin((void *)argp);
982cb5caa98Sdjl 		if (len == 0)
983cb5caa98Sdjl 			break;
984cb5caa98Sdjl 
985cb5caa98Sdjl 		/* size of door buffer not big enough, allocate one */
986cb5caa98Sdjl 		NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
987cb5caa98Sdjl 
988cb5caa98Sdjl 		/* copy packed header */
989cb5caa98Sdjl 		*(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
990cb5caa98Sdjl 
991cb5caa98Sdjl 		/* set new buffer size */
992cb5caa98Sdjl 		((nss_pheader_t *)uptr)->pbufsiz = buflen;
993cb5caa98Sdjl 
994cb5caa98Sdjl 		/* try one more time */
995cb5caa98Sdjl 		(void) _nscd_door_getadmin((void *)uptr);
996cb5caa98Sdjl 		(void) door_return(uptr, buflen, NULL, 0);
997cb5caa98Sdjl 		break;
998cb5caa98Sdjl 
999cb5caa98Sdjl 	case NSCD_SETADMIN:
1000cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_SETADMIN");
1001cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr))
1002cb5caa98Sdjl 			_nscd_door_setadmin(argp);
1003cb5caa98Sdjl 		break;
1004cb5caa98Sdjl 
1005cb5caa98Sdjl 	case NSCD_KILLSERVER:
1006cb5caa98Sdjl 		N2N_check_priv(argp, "NSCD_KILLSERVER");
1007cb5caa98Sdjl 		if (NSCD_STATUS_IS_OK(phdr)) {
1008cb5caa98Sdjl 			/* also kill the forker nscd if one is running */
1009cb5caa98Sdjl 			_nscd_kill_forker();
1010cb5caa98Sdjl 			exit(0);
1011cb5caa98Sdjl 		}
1012cb5caa98Sdjl 		break;
1013cb5caa98Sdjl 
1014cb5caa98Sdjl 	default:
1015cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1016cb5caa98Sdjl 		(me, "Unknown name service door call op %d\n",
1017cb5caa98Sdjl 			phdr->nsc_callnumber);
1018cb5caa98Sdjl 
1019cb5caa98Sdjl 		NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1020cb5caa98Sdjl 
1021cb5caa98Sdjl 		(void) door_return(argp, arg_size, NULL, 0);
1022cb5caa98Sdjl 		break;
1023cb5caa98Sdjl 
1024cb5caa98Sdjl 	}
1025cb5caa98Sdjl 	(void) door_return(argp, arg_size, NULL, 0);
1026cb5caa98Sdjl }
1027cb5caa98Sdjl 
1028cb5caa98Sdjl int
1029cb5caa98Sdjl _nscd_setup_server(char *execname, char **argv)
1030cb5caa98Sdjl {
1031cb5caa98Sdjl 
1032cb5caa98Sdjl 	int		fd;
1033cb5caa98Sdjl 	int		errnum;
1034cb5caa98Sdjl 	int		bind_failed = 0;
1035cb5caa98Sdjl 	struct stat	buf;
1036cb5caa98Sdjl 	sigset_t	myset;
1037cb5caa98Sdjl 	struct sigaction action;
1038cb5caa98Sdjl 	char		*me = "_nscd_setup_server";
1039cb5caa98Sdjl 
1040cb5caa98Sdjl 	main_execname = execname;
1041cb5caa98Sdjl 	main_argv = argv;
1042cb5caa98Sdjl 
1043cb5caa98Sdjl 	keep_open_dns_socket();
1044cb5caa98Sdjl 
1045cb5caa98Sdjl 	/*
1046cb5caa98Sdjl 	 * the max number of server threads should be fixed now, so
1047cb5caa98Sdjl 	 * set flag to indicate that no in-flight change is allowed
1048cb5caa98Sdjl 	 */
1049cb5caa98Sdjl 	max_servers_set = 1;
1050cb5caa98Sdjl 
1051cb5caa98Sdjl 	(void) thr_keycreate(&lookup_state_key, NULL);
1052cb5caa98Sdjl 	(void) sema_init(&common_sema,
1053cb5caa98Sdjl 			frontend_cfg_g.common_worker_threads,
1054cb5caa98Sdjl 			USYNC_THREAD, 0);
1055cb5caa98Sdjl 
1056cb5caa98Sdjl 	/* Establish server thread pool */
1057cb5caa98Sdjl 	(void) door_server_create(server_create);
1058cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
1059cb5caa98Sdjl 		errnum = errno;
1060cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1061cb5caa98Sdjl 		(me, "thr_keycreate (server thread): %s\n",
1062cb5caa98Sdjl 			strerror(errnum));
1063cb5caa98Sdjl 		return (-1);
1064cb5caa98Sdjl 	}
1065cb5caa98Sdjl 
1066cb5caa98Sdjl 	/* Create a door */
1067cb5caa98Sdjl 	if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1068cb5caa98Sdjl 	    DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
1069cb5caa98Sdjl 		errnum = errno;
1070cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1071cb5caa98Sdjl 		(me, "door_create: %s\n", strerror(errnum));
1072cb5caa98Sdjl 		return (-1);
1073cb5caa98Sdjl 	}
1074cb5caa98Sdjl 
1075cb5caa98Sdjl 	/* if not main nscd, no more setup to do */
1076cb5caa98Sdjl 	if (_whoami != NSCD_MAIN)
1077cb5caa98Sdjl 		return (fd);
1078cb5caa98Sdjl 
1079cb5caa98Sdjl 	/* bind to file system */
1080cb5caa98Sdjl 	if (is_system_labeled()) {
1081cb5caa98Sdjl 		if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
1082cb5caa98Sdjl 			int newfd;
1083cb5caa98Sdjl 			if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
1084cb5caa98Sdjl 				errnum = errno;
1085cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1086cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1087cb5caa98Sdjl 				(me, "Cannot create %s: %s\n",
1088cb5caa98Sdjl 					TSOL_NAME_SERVICE_DOOR,
1089cb5caa98Sdjl 					strerror(errnum));
1090cb5caa98Sdjl 				bind_failed = 1;
1091cb5caa98Sdjl 			}
1092cb5caa98Sdjl 			(void) close(newfd);
1093cb5caa98Sdjl 		}
1094cb5caa98Sdjl 		if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
1095cb5caa98Sdjl 			if (errno != EEXIST) {
1096cb5caa98Sdjl 				errnum = errno;
1097cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1098cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1099cb5caa98Sdjl 				(me, "Cannot symlink %s: %s\n",
1100cb5caa98Sdjl 					NAME_SERVICE_DOOR,
1101cb5caa98Sdjl 					strerror(errnum));
1102cb5caa98Sdjl 				bind_failed = 1;
1103cb5caa98Sdjl 			}
1104cb5caa98Sdjl 		}
1105cb5caa98Sdjl 	} else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
1106cb5caa98Sdjl 		int newfd;
1107cb5caa98Sdjl 		if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
1108cb5caa98Sdjl 			errnum = errno;
1109cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1110cb5caa98Sdjl 			(me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
1111cb5caa98Sdjl 				strerror(errnum));
1112cb5caa98Sdjl 			bind_failed = 1;
1113cb5caa98Sdjl 		}
1114cb5caa98Sdjl 		(void) close(newfd);
1115cb5caa98Sdjl 	}
1116cb5caa98Sdjl 
1117cb5caa98Sdjl 	if (bind_failed == 1) {
1118cb5caa98Sdjl 		(void) door_revoke(fd);
1119cb5caa98Sdjl 		return (-1);
1120cb5caa98Sdjl 	}
1121cb5caa98Sdjl 
1122cb5caa98Sdjl 	if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
1123cb5caa98Sdjl 		if ((errno != EBUSY) ||
1124cb5caa98Sdjl 		(fdetach(NAME_SERVICE_DOOR) <  0) ||
1125cb5caa98Sdjl 		(fattach(fd, NAME_SERVICE_DOOR) < 0)) {
1126cb5caa98Sdjl 			errnum = errno;
1127cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END,
1128cb5caa98Sdjl 				NSCD_LOG_LEVEL_ERROR)
1129cb5caa98Sdjl 			(me, "fattach: %s\n", strerror(errnum));
1130cb5caa98Sdjl 			(void) door_revoke(fd);
1131cb5caa98Sdjl 			return (-1);
1132cb5caa98Sdjl 		}
1133cb5caa98Sdjl 	}
1134cb5caa98Sdjl 
1135cb5caa98Sdjl 	/*
1136cb5caa98Sdjl 	 * kick off routing socket monitor thread
1137cb5caa98Sdjl 	 */
1138cb5caa98Sdjl 	if (thr_create(NULL, NULL,
1139cb5caa98Sdjl 		(void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1140cb5caa98Sdjl 		errnum = errno;
1141cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1142cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
1143cb5caa98Sdjl 			strerror(errnum));
1144cb5caa98Sdjl 
1145cb5caa98Sdjl 		(void) door_revoke(fd);
1146cb5caa98Sdjl 		return (-1);
1147cb5caa98Sdjl 	}
1148cb5caa98Sdjl 
1149cb5caa98Sdjl 	/*
1150cb5caa98Sdjl 	 * set up signal handler for SIGHUP
1151cb5caa98Sdjl 	 */
1152cb5caa98Sdjl 	action.sa_handler = dozip;
1153cb5caa98Sdjl 	action.sa_flags = 0;
1154cb5caa98Sdjl 	(void) sigemptyset(&action.sa_mask);
1155cb5caa98Sdjl 	(void) sigemptyset(&myset);
1156cb5caa98Sdjl 	(void) sigaddset(&myset, SIGHUP);
1157cb5caa98Sdjl 
1158cb5caa98Sdjl 	if (sigaction(SIGHUP, &action, NULL) < 0) {
1159cb5caa98Sdjl 		errnum = errno;
1160cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1161cb5caa98Sdjl 		(me, "sigaction (SIGHUP): %s\n", strerror(errnum));
1162cb5caa98Sdjl 
1163cb5caa98Sdjl 		(void) door_revoke(fd);
1164cb5caa98Sdjl 		return (-1);
1165cb5caa98Sdjl 	}
1166cb5caa98Sdjl 
1167cb5caa98Sdjl 	return (fd);
1168cb5caa98Sdjl }
1169cb5caa98Sdjl 
1170cb5caa98Sdjl int
1171cb5caa98Sdjl _nscd_setup_child_server(int did)
1172cb5caa98Sdjl {
1173cb5caa98Sdjl 
1174cb5caa98Sdjl 	int		errnum;
1175cb5caa98Sdjl 	int		fd;
1176cb5caa98Sdjl 	nscd_rc_t	rc;
1177cb5caa98Sdjl 	char		*me = "_nscd_setup_child_server";
1178cb5caa98Sdjl 
1179cb5caa98Sdjl 	/* Re-establish our own server thread pool */
1180cb5caa98Sdjl 	(void) door_server_create(server_create);
1181cb5caa98Sdjl 	if (thr_keycreate(&server_key, server_destroy) != 0) {
1182cb5caa98Sdjl 		errnum = errno;
1183cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1184cb5caa98Sdjl 		(me, "thr_keycreate failed: %s", strerror(errnum));
1185cb5caa98Sdjl 		return (-1);
1186cb5caa98Sdjl 	}
1187cb5caa98Sdjl 
1188cb5caa98Sdjl 	/*
1189cb5caa98Sdjl 	 * Create a new door.
1190cb5caa98Sdjl 	 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1191cb5caa98Sdjl 	 */
1192cb5caa98Sdjl 	(void) close(did);
1193cb5caa98Sdjl 	if ((fd = door_create(switcher,
1194cb5caa98Sdjl 		NAME_SERVICE_DOOR_COOKIE,
1195cb5caa98Sdjl 		DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
1196cb5caa98Sdjl 		errnum = errno;
1197cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1198cb5caa98Sdjl 		(me, "door_create failed: %s", strerror(errnum));
1199cb5caa98Sdjl 		return (-1);
1200cb5caa98Sdjl 	}
1201cb5caa98Sdjl 
1202cb5caa98Sdjl 	/*
1203cb5caa98Sdjl 	 * kick off routing socket monitor thread
1204cb5caa98Sdjl 	 */
1205cb5caa98Sdjl 	if (thr_create(NULL, NULL,
1206cb5caa98Sdjl 		(void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1207cb5caa98Sdjl 		errnum = errno;
1208cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1209cb5caa98Sdjl 		(me, "thr_create (routing socket monitor): %s\n",
1210cb5caa98Sdjl 			strerror(errnum));
1211cb5caa98Sdjl 		(void) door_revoke(fd);
1212cb5caa98Sdjl 		return (-1);
1213cb5caa98Sdjl 	}
1214cb5caa98Sdjl 
1215cb5caa98Sdjl 	/*
1216cb5caa98Sdjl 	 * start monitoring the states of the name service clients
1217cb5caa98Sdjl 	 */
1218cb5caa98Sdjl 	rc = _nscd_init_smf_monitor();
1219cb5caa98Sdjl 	if (rc != NSCD_SUCCESS) {
1220cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1221cb5caa98Sdjl 	(me, "unable to start the SMF monitor (rc = %d)\n", rc);
1222cb5caa98Sdjl 
1223cb5caa98Sdjl 		(void) door_revoke(fd);
1224cb5caa98Sdjl 		return (-1);
1225cb5caa98Sdjl 	}
1226cb5caa98Sdjl 
1227cb5caa98Sdjl 	return (fd);
1228cb5caa98Sdjl }
1229cb5caa98Sdjl 
1230cb5caa98Sdjl nscd_rc_t
1231cb5caa98Sdjl _nscd_alloc_frontend_cfg()
1232cb5caa98Sdjl {
1233cb5caa98Sdjl 	frontend_cfg  = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
1234cb5caa98Sdjl 	if (frontend_cfg == NULL)
1235cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
1236cb5caa98Sdjl 
1237cb5caa98Sdjl 	return (NSCD_SUCCESS);
1238cb5caa98Sdjl }
1239cb5caa98Sdjl 
1240cb5caa98Sdjl 
1241cb5caa98Sdjl /* ARGSUSED */
1242cb5caa98Sdjl nscd_rc_t
1243cb5caa98Sdjl _nscd_cfg_frontend_notify(
1244cb5caa98Sdjl 	void				*data,
1245cb5caa98Sdjl 	struct nscd_cfg_param_desc	*pdesc,
1246cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1247cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
1248cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
1249cb5caa98Sdjl 	void				*cookie)
1250cb5caa98Sdjl {
1251cb5caa98Sdjl 	void				*dp;
1252cb5caa98Sdjl 
1253cb5caa98Sdjl 	/*
1254cb5caa98Sdjl 	 * At init time, the whole group of config params are received.
1255cb5caa98Sdjl 	 * At update time, group or individual parameter value could
1256cb5caa98Sdjl 	 * be received.
1257cb5caa98Sdjl 	 */
1258cb5caa98Sdjl 
1259cb5caa98Sdjl 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
1260cb5caa98Sdjl 		_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1261cb5caa98Sdjl 		/*
1262cb5caa98Sdjl 		 * group data is received, copy in the
1263cb5caa98Sdjl 		 * entire strcture
1264cb5caa98Sdjl 		 */
1265cb5caa98Sdjl 		if (_nscd_cfg_flag_is_set(pdesc->pflag,
1266cb5caa98Sdjl 			NSCD_CFG_PFLAG_GLOBAL))
1267cb5caa98Sdjl 			frontend_cfg_g =
1268cb5caa98Sdjl 				*(nscd_cfg_global_frontend_t *)data;
1269cb5caa98Sdjl 		else
1270cb5caa98Sdjl 			frontend_cfg[nswdb->index] =
1271cb5caa98Sdjl 				*(nscd_cfg_frontend_t *)data;
1272cb5caa98Sdjl 
1273cb5caa98Sdjl 	} else {
1274cb5caa98Sdjl 		/*
1275cb5caa98Sdjl 		 * individual paramater is received: copy in the
1276cb5caa98Sdjl 		 * parameter value.
1277cb5caa98Sdjl 		 */
1278cb5caa98Sdjl 		if (_nscd_cfg_flag_is_set(pdesc->pflag,
1279cb5caa98Sdjl 			NSCD_CFG_PFLAG_GLOBAL))
1280cb5caa98Sdjl 			dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1281cb5caa98Sdjl 		else
1282cb5caa98Sdjl 			dp = (char *)&frontend_cfg[nswdb->index] +
1283cb5caa98Sdjl 				pdesc->p_offset;
1284cb5caa98Sdjl 		(void) memcpy(dp, data, pdesc->p_size);
1285cb5caa98Sdjl 	}
1286cb5caa98Sdjl 
1287cb5caa98Sdjl 	return (NSCD_SUCCESS);
1288cb5caa98Sdjl }
1289cb5caa98Sdjl 
1290cb5caa98Sdjl /* ARGSUSED */
1291cb5caa98Sdjl nscd_rc_t
1292cb5caa98Sdjl _nscd_cfg_frontend_verify(
1293cb5caa98Sdjl 	void				*data,
1294cb5caa98Sdjl 	struct	nscd_cfg_param_desc	*pdesc,
1295cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1296cb5caa98Sdjl 	nscd_cfg_flag_t			dflag,
1297cb5caa98Sdjl 	nscd_cfg_error_t		**errorp,
1298cb5caa98Sdjl 	void				**cookie)
1299cb5caa98Sdjl {
1300cb5caa98Sdjl 
1301cb5caa98Sdjl 	char				*me = "_nscd_cfg_frontend_verify";
1302cb5caa98Sdjl 
1303cb5caa98Sdjl 	/*
1304cb5caa98Sdjl 	 * if max. number of server threads is set and in effect,
1305cb5caa98Sdjl 	 * don't allow changing of the frontend configuration
1306cb5caa98Sdjl 	 */
1307cb5caa98Sdjl 	if (max_servers_set) {
1308cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1309cb5caa98Sdjl 	(me, "changing of the frontend configuration not allowed now");
1310cb5caa98Sdjl 
1311cb5caa98Sdjl 		return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1312cb5caa98Sdjl 	}
1313cb5caa98Sdjl 
1314cb5caa98Sdjl 	return (NSCD_SUCCESS);
1315cb5caa98Sdjl }
1316cb5caa98Sdjl 
1317cb5caa98Sdjl /* ARGSUSED */
1318cb5caa98Sdjl nscd_rc_t
1319cb5caa98Sdjl _nscd_cfg_frontend_get_stat(
1320cb5caa98Sdjl 	void				**stat,
1321cb5caa98Sdjl 	struct nscd_cfg_stat_desc	*sdesc,
1322cb5caa98Sdjl 	nscd_cfg_id_t			*nswdb,
1323cb5caa98Sdjl 	nscd_cfg_flag_t			*dflag,
1324cb5caa98Sdjl 	void				(**free_stat)(void *stat),
1325cb5caa98Sdjl 	nscd_cfg_error_t		**errorp)
1326cb5caa98Sdjl {
1327cb5caa98Sdjl 	return (NSCD_SUCCESS);
1328cb5caa98Sdjl }
1329cb5caa98Sdjl 
1330cb5caa98Sdjl void
1331cb5caa98Sdjl _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1332cb5caa98Sdjl {
1333cb5caa98Sdjl 	int	i, j;
1334cb5caa98Sdjl 	char	*dbn;
1335cb5caa98Sdjl 
1336cb5caa98Sdjl 	if (max_servers == 0)
1337cb5caa98Sdjl 		max_servers = frontend_cfg_g.common_worker_threads +
1338cb5caa98Sdjl 		frontend_cfg_g.cache_hit_threads;
1339cb5caa98Sdjl 
1340cb5caa98Sdjl 	for (i = 0; i < NSCD_NUM_DB; i++) {
1341cb5caa98Sdjl 
1342cb5caa98Sdjl 		dbn = NSCD_NSW_DB_NAME(i);
1343cb5caa98Sdjl 		if (strcasecmp(dbn, cache_name) == 0) {
1344cb5caa98Sdjl 			j = frontend_cfg[i].worker_thread_per_nsw_db;
1345cb5caa98Sdjl 			(void) sema_init(sema, j, USYNC_THREAD, 0);
1346cb5caa98Sdjl 			max_servers += j;
1347cb5caa98Sdjl 			break;
1348cb5caa98Sdjl 		}
1349cb5caa98Sdjl 	}
1350cb5caa98Sdjl }
1351cb5caa98Sdjl 
1352cb5caa98Sdjl /*
1353cb5caa98Sdjl  * Monitor the routing socket.  Address lists stored in the ipnodes
1354cb5caa98Sdjl  * cache are sorted based on destination address selection rules,
1355cb5caa98Sdjl  * so when things change that could affect that sorting (interfaces
1356cb5caa98Sdjl  * go up or down, flags change, etc.), we clear that cache so the
1357cb5caa98Sdjl  * list will be re-ordered the next time the hostname is resolved.
1358cb5caa98Sdjl  */
1359cb5caa98Sdjl static void
1360cb5caa98Sdjl rts_mon(void)
1361cb5caa98Sdjl {
1362cb5caa98Sdjl 	int	rt_sock, rdlen, idx;
1363cb5caa98Sdjl 	union {
1364cb5caa98Sdjl 		struct {
1365cb5caa98Sdjl 			struct rt_msghdr rtm;
1366cb5caa98Sdjl 			struct sockaddr_storage addrs[RTA_NUMBITS];
1367cb5caa98Sdjl 		} r;
1368cb5caa98Sdjl 		struct if_msghdr ifm;
1369cb5caa98Sdjl 		struct ifa_msghdr ifam;
1370cb5caa98Sdjl 	} mbuf;
1371cb5caa98Sdjl 	struct ifa_msghdr *ifam = &mbuf.ifam;
1372cb5caa98Sdjl 	char	*me = "rts_mon";
1373cb5caa98Sdjl 
1374cb5caa98Sdjl 	rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1375cb5caa98Sdjl 	if (rt_sock < 0) {
1376cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1377cb5caa98Sdjl 		(me, "Failed to open routing socket: %s\n", strerror(errno));
1378cb5caa98Sdjl 		thr_exit(0);
1379cb5caa98Sdjl 	}
1380cb5caa98Sdjl 
1381cb5caa98Sdjl 	for (;;) {
1382cb5caa98Sdjl 		rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1383cb5caa98Sdjl 		if (rdlen <= 0) {
1384cb5caa98Sdjl 			if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1385cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1386cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1387cb5caa98Sdjl 				(me, "routing socket read: %s\n",
1388cb5caa98Sdjl 					strerror(errno));
1389cb5caa98Sdjl 				thr_exit(0);
1390cb5caa98Sdjl 			}
1391cb5caa98Sdjl 			continue;
1392cb5caa98Sdjl 		}
1393cb5caa98Sdjl 		if (ifam->ifam_version != RTM_VERSION) {
1394cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_FRONT_END,
1395cb5caa98Sdjl 					NSCD_LOG_LEVEL_ERROR)
1396cb5caa98Sdjl 				(me, "rx unknown version (%d) on "
1397cb5caa98Sdjl 					"routing socket.\n",
1398cb5caa98Sdjl 					ifam->ifam_version);
1399cb5caa98Sdjl 			continue;
1400cb5caa98Sdjl 		}
1401cb5caa98Sdjl 		switch (ifam->ifam_type) {
1402cb5caa98Sdjl 		case RTM_NEWADDR:
1403cb5caa98Sdjl 		case RTM_DELADDR:
1404cb5caa98Sdjl 			/* if no ipnodes cache, then nothing to do */
1405cb5caa98Sdjl 			idx = get_cache_idx("ipnodes");
1406cb5caa98Sdjl 			if (cache_ctx_p[idx] == NULL ||
1407cb5caa98Sdjl 				cache_ctx_p[idx]->reaper_on != nscd_true)
1408cb5caa98Sdjl 				break;
1409cb5caa98Sdjl 			nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1410cb5caa98Sdjl 			break;
1411cb5caa98Sdjl 		case RTM_ADD:
1412cb5caa98Sdjl 		case RTM_DELETE:
1413cb5caa98Sdjl 		case RTM_CHANGE:
1414cb5caa98Sdjl 		case RTM_GET:
1415cb5caa98Sdjl 		case RTM_LOSING:
1416cb5caa98Sdjl 		case RTM_REDIRECT:
1417cb5caa98Sdjl 		case RTM_MISS:
1418cb5caa98Sdjl 		case RTM_LOCK:
1419cb5caa98Sdjl 		case RTM_OLDADD:
1420cb5caa98Sdjl 		case RTM_OLDDEL:
1421cb5caa98Sdjl 		case RTM_RESOLVE:
1422cb5caa98Sdjl 		case RTM_IFINFO:
1423cb5caa98Sdjl 			break;
1424cb5caa98Sdjl 		default:
1425cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1426cb5caa98Sdjl 			(me, "rx unknown msg type (%d) on routing socket.\n",
1427cb5caa98Sdjl 			    ifam->ifam_type);
1428cb5caa98Sdjl 			break;
1429cb5caa98Sdjl 		}
1430cb5caa98Sdjl 	}
1431cb5caa98Sdjl }
1432cb5caa98Sdjl 
1433cb5caa98Sdjl static void
1434cb5caa98Sdjl keep_open_dns_socket(void)
1435cb5caa98Sdjl {
1436cb5caa98Sdjl 	_res.options |= RES_STAYOPEN; /* just keep this udp socket open */
1437cb5caa98Sdjl }
1438