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