xref: /titanic_50/usr/src/cmd/nscd/nscd_selfcred.c (revision c529a23fbecacf8a1e97ef658aa4bd8d2e2953b9)
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 2006 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 <stdio.h>
29 #include <stdlib.h>
30 #include <synch.h>
31 #include <thread.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <dlfcn.h>
35 #include <door.h>
36 #include <libscf.h>
37 #include <ucred.h>
38 #include <sys/varargs.h>
39 #include <signal.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <dirent.h>
43 #include <sys/proc.h>
44 #include <procfs.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <limits.h>
48 #include <sys/resource.h>
49 #include <libscf.h>
50 #include "nscd_door.h"
51 #include "nscd_config.h"
52 #include "nscd_log.h"
53 #include "nscd_frontend.h"
54 #include "nscd_selfcred.h"
55 #include "nscd_admin.h"
56 #include "nscd_common.h"
57 #include "ns_sldap.h"
58 
59 extern int	_logfd;
60 static char	*execpath;
61 static char	**execargv;
62 static char	*selfcred_dbs = NULL;
63 
64 static void *get_smf_prop(const char *var, char type, void *def_val);
65 
66 /* current self-cred configuration data being used */
67 static nscd_cfg_global_selfcred_t	nscd_selfcred_cfg_g;
68 
69 #define	_NSCD_PUN_BLOCK	1024
70 static uint8_t  pu_nscd_enabled;
71 static int	max_pu_nscd = _NSCD_PUN_BLOCK;
72 static int	pu_nscd_ttl;
73 
74 static nscd_rc_t setup_ldap_backend();
75 static nscd_rc_t init_user_proc_monitor();
76 
77 /*
78  * clild state
79  */
80 typedef enum {
81 	CHILD_STATE_NONE	= 0,
82 	CHILD_STATE_UIDKNOWN,
83 	CHILD_STATE_FORKSENT,
84 	CHILD_STATE_PIDKNOWN
85 } child_state_t;
86 
87 
88 typedef struct _child {
89 	int		child_slot;
90 	int		child_door;
91 	pid_t		child_pid;
92 	uid_t		child_uid;
93 	gid_t		child_gid;
94 	child_state_t	child_state;
95 	int		next_open;
96 	mutex_t		*mutex;
97 	cond_t		*cond;
98 } child_t;
99 
100 static child_t	**child = NULL;
101 static mutex_t	child_lock = DEFAULTMUTEX;
102 static int	open_head;
103 static int	open_tail;
104 static int	used_slot;
105 
106 /* nscd door id */
107 extern int _doorfd;
108 static pid_t main_uid = 0;
109 
110 /* nscd id: main, forker, or child */
111 extern int _whoami;
112 
113 /* forker nscd pid */
114 static pid_t forker_pid = 0;
115 static pid_t forker_uid = 0;
116 
117 long		activity = 0;
118 mutex_t		activity_lock = DEFAULTMUTEX;
119 
120 static int	forking_door = -1;
121 static mutex_t	forking_lock = DEFAULTMUTEX;
122 
123 static void
124 free_slot(int	s)
125 {
126 	if (child[s] == NULL)
127 		return;
128 	free(child[s]->mutex);
129 	free(child[s]->cond);
130 	free(child[s]);
131 	child[s] = NULL;
132 }
133 
134 void
135 _nscd_free_cslots()
136 {
137 
138 	int i;
139 
140 	(void) mutex_lock(&child_lock);
141 
142 	for (i = 0; i < max_pu_nscd; i++)
143 		free_slot(i);
144 
145 	open_head = -1;
146 	open_tail = -1;
147 	used_slot = -1;
148 
149 	(void) mutex_unlock(&child_lock);
150 
151 }
152 
153 static int
154 init_slot(int	s)
155 {
156 	child_t	*ch;
157 	char	*me = "init_slot";
158 
159 	if (child[s] == NULL) {
160 		child[s] = (child_t *)calloc(1, sizeof (child_t));
161 		if (child[s] == NULL)
162 			return (-1);
163 		ch = child[s];
164 
165 		if ((ch->mutex = (mutex_t *)calloc(1,
166 			sizeof (mutex_t))) == NULL) {
167 			free(ch);
168 			return (-1);
169 		}
170 		(void) mutex_init(ch->mutex, USYNC_THREAD, NULL);
171 
172 		if ((ch->cond = (cond_t *)calloc(1,
173 			sizeof (cond_t))) == NULL) {
174 			free(ch->mutex);
175 			free(ch);
176 			return (-1);
177 		}
178 		(void) cond_init(ch->cond, USYNC_THREAD, NULL);
179 
180 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
181 		(me, "slot %d allocated\n", s);
182 	} else
183 		ch = child[s];
184 
185 	ch->child_slot = s;
186 	ch->child_door = 0;
187 	ch->child_state = CHILD_STATE_NONE;
188 	ch->child_pid = 0;
189 	ch->child_uid = 0;
190 	ch->child_gid = 0;
191 	ch->next_open = -1;
192 
193 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
194 	(me, "slot %d initialized\n", s);
195 
196 	return (0);
197 }
198 
199 static int
200 _nscd_init_cslots()
201 {
202 	(void) mutex_lock(&child_lock);
203 
204 	child = (child_t **)calloc(max_pu_nscd, sizeof (child_t *));
205 	if (child == NULL)
206 		return (-1);
207 
208 	open_head = -1;
209 	open_tail = -1;
210 	used_slot = -1;
211 
212 	(void) mutex_unlock(&child_lock);
213 
214 	return (0);
215 }
216 
217 static child_t *
218 get_cslot(
219 	uid_t		uid,
220 	int		no_alloc)
221 {
222 	int		i;
223 	child_t		*ch, *ret = NULL;
224 	char		*me = "get_cslot";
225 
226 	(void) mutex_lock(&child_lock);
227 
228 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
229 	(me, "looking for uid %d (slot used = %d)\n", uid, used_slot);
230 
231 	/* first find the slot with a matching uid */
232 	for (i = 0; i <= used_slot; i++) {
233 		ch = child[i];
234 		if (ch->child_state >= CHILD_STATE_UIDKNOWN &&
235 			ch->child_uid == uid) {
236 			ret = ch;
237 			(void) mutex_unlock(&child_lock);
238 
239 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
240 			(me, "slot %d found with uid %d\n",
241 				ret->child_slot, ret->child_uid);
242 
243 			return (ret);
244 		}
245 	}
246 
247 	/* if no need to allocate a new slot, return NULL */
248 	if (no_alloc == 1) {
249 		(void) mutex_unlock(&child_lock);
250 		return (ret);
251 	}
252 
253 	/* no open slot ? get a new one */
254 	if (open_head == -1) {
255 		/* if no slot available, allocate more */
256 		if (used_slot >= max_pu_nscd - 1) {
257 			child_t	**tmp;
258 			int	newmax = max_pu_nscd + _NSCD_PUN_BLOCK;
259 
260 			tmp = (child_t **)calloc(newmax, sizeof (child_t *));
261 			if (tmp == NULL) {
262 				(void) mutex_unlock(&child_lock);
263 				return (ret);
264 			}
265 			(void) memcpy(tmp, child, sizeof (child_t) *
266 				max_pu_nscd);
267 			free(child);
268 			child = tmp;
269 			max_pu_nscd = newmax;
270 		}
271 		used_slot++;
272 		if (init_slot(used_slot) == -1) {
273 			used_slot--;
274 			(void) mutex_unlock(&child_lock);
275 			return (ret);
276 		}
277 		ch = child[used_slot];
278 	} else {
279 		ch = child[open_head];
280 		open_head = ch->next_open;
281 		/* got last one ? reset tail */
282 		if (open_head == -1)
283 			open_tail = -1;
284 		ch->next_open = -1;
285 	}
286 
287 	ch->child_uid = uid;
288 	ch->child_state = CHILD_STATE_UIDKNOWN;
289 	ret = ch;
290 
291 	(void) mutex_unlock(&child_lock);
292 
293 	return (ret);
294 }
295 
296 static void
297 return_cslot_nolock(child_t *ch)
298 {
299 
300 	int	slot = ch->child_slot;
301 
302 	/* have open slot ? add to and reset tail */
303 	if (open_tail != -1) {
304 		child[open_tail]->next_open = slot;
305 		open_tail = slot;
306 	} else {
307 		/* no open slot ? make one */
308 		open_head = open_tail = slot;
309 	}
310 
311 	(void) init_slot(ch->child_slot);
312 }
313 
314 static void
315 return_cslot(child_t *ch)
316 {
317 
318 	char *me = "return_cslot";
319 
320 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
321 	(me, "returning slot %d\n", ch->child_slot);
322 
323 	/* return if the slot has been returned by another thread */
324 	if (ch->child_state == CHILD_STATE_NONE)
325 		return;
326 
327 	(void) mutex_lock(&child_lock);
328 
329 	/* check one more time */
330 	if (ch->child_state == CHILD_STATE_NONE) {
331 		(void) mutex_unlock(&child_lock);
332 		return;
333 	}
334 
335 	return_cslot_nolock(ch);
336 
337 	(void) mutex_unlock(&child_lock);
338 }
339 
340 static int
341 selfcred_kill(
342 	int	fd)
343 {
344 	int	ret;
345 	char	*me = "selfcred_kill";
346 
347 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
348 	(me, "sending kill to door %d\n", fd);
349 
350 	if (fd != -1)
351 		ret = _nscd_doorcall_fd(fd, NSCD_KILL, NULL, 0,
352 			NULL, 0, NULL);
353 	else
354 		ret = _nscd_doorcall(NSCD_KILL);
355 
356 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
357 	(me, "kill request sent to door %d (rc = %d)\n", fd, ret);
358 
359 	return (ret);
360 }
361 
362 
363 void
364 _nscd_kill_forker()
365 {
366 	(void) mutex_lock(&forking_lock);
367 	if (forking_door != -1)
368 		(void) selfcred_kill(forking_door);
369 	forking_door = -1;
370 	(void) mutex_unlock(&forking_lock);
371 }
372 
373 void
374 _nscd_kill_all_children()
375 {
376 	int	i;
377 	int	ret;
378 	char	*me = "_nscd_kill_all_children";
379 
380 	(void) mutex_lock(&child_lock);
381 	for (i = 0; i <= used_slot; i++) {
382 		if (child[i] == NULL)
383 			continue;
384 
385 		if (child[i]->child_state >= CHILD_STATE_PIDKNOWN) {
386 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
387 			(me, "killing child process %d (doorfd %d)\n",
388 			child[i]->child_pid, child[i]->child_door);
389 
390 			ret = selfcred_kill(child[i]->child_door);
391 
392 			if (ret != -1)
393 				(void) kill(child[i]->child_pid, SIGTERM);
394 		}
395 		if (child[i]->child_state != CHILD_STATE_NONE)
396 			(void) return_cslot_nolock(child[i]);
397 	}
398 	(void) mutex_unlock(&child_lock);
399 }
400 static int
401 selfcred_pulse(
402 	int		fd)
403 {
404 	int		ret;
405 	char		*me = "selfcred_pulse";
406 
407 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
408 	(me, "start monitoring door %d\n", fd);
409 
410 	ret = _nscd_doorcall_fd(fd, NSCD_PULSE |(_whoami & NSCD_WHOAMI),
411 		NULL, 0, NULL, 0, NULL);
412 
413 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
414 	(me, "door (%d) monitor exited (rc = %d)\n", fd, ret);
415 
416 	return (ret);
417 }
418 
419 /*ARGSUSED*/
420 static void *
421 forker_monitor(
422 	void		*arg)
423 {
424 	pid_t		fpid;
425 	char		*fmri;
426 	char		*me = "forker_monitor";
427 
428 	/* wait until forker exits */
429 	fpid = forker_pid;
430 	(void) selfcred_pulse(forking_door);
431 
432 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
433 (me, "forker (pid = %d) exited or crashed, killing all child processes\n",
434 		fpid);
435 
436 	(void) mutex_lock(&forking_lock);
437 	forking_door = -1;
438 	forker_pid = -1;
439 	(void) mutex_unlock(&forking_lock);
440 
441 	/* forker exited/crashed, kill all the child processes */
442 	_nscd_kill_all_children();
443 
444 	/* restart forker */
445 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
446 	(me, "restarting the forker ...\n");
447 
448 	switch (fpid = fork1()) {
449 	case (pid_t)-1:
450 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
451 		(me, "unable to fork and start the forker ...\n");
452 
453 		/* enter the maintenance mode */
454 		if ((fmri = getenv("SMF_FMRI")) != NULL) {
455 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
456 			(me, "entering maintenance mode ...\n");
457 			smf_maintain_instance(fmri, SMF_TEMPORARY);
458 		}
459 		thr_exit((void *)1);
460 		break;
461 	case 0:
462 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
463 		(me, "execv path = %s\n", execpath);
464 
465 		(void) execv(execpath, execargv);
466 		exit(0);
467 		break;
468 	default:
469 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
470 		(me, "new forker's pid is %d\n", fpid);
471 		forker_pid = fpid;
472 		break;
473 	}
474 
475 	thr_exit((void *)0);
476 
477 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
478 }
479 
480 static void *
481 child_monitor(
482 	void		*arg)
483 {
484 	child_t		*ch = (child_t *)arg;
485 	pid_t		cpid;
486 	char		*me = "child_monitor";
487 
488 	/* wait until child exits */
489 	cpid = ch->child_pid;
490 	(void) selfcred_pulse(ch->child_door);
491 
492 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
493 		(me, "child (pid = %d) exited or crashed ...\n", cpid);
494 
495 	/* return the slot used by the child */
496 	return_cslot(ch);
497 
498 	thr_exit((void *)0);
499 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
500 }
501 
502 
503 void
504 _nscd_proc_iamhere(
505 	void		*buf,
506 	door_desc_t	*dp,
507 	uint_t		n_desc,
508 	int		iam)
509 {
510 	int		cslot;
511 	child_t		*ch;
512 	int		errnum;
513 	ucred_t		*uc = NULL;
514 	uid_t		uid;
515 	nscd_imhere_t	*ih;
516 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
517 	char		*me = "_nscd_proc_iamhere";
518 
519 
520 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
521 	(me, "%d receives iamhere from %d\n", _whoami, iam);
522 
523 	if (door_ucred(&uc) != 0) {
524 		errnum = errno;
525 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
526 		(me, "door_ucred failed: %s\n", strerror(errnum));
527 
528 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
529 			NSCD_DOOR_UCRED_ERROR);
530 	}
531 	uid = ucred_geteuid(uc);
532 
533 	switch (iam) {
534 
535 	case NSCD_MAIN:
536 		if (_whoami == NSCD_MAIN || uid != main_uid) {
537 			/*
538 			 * I'm main, or uid from door is not correct,
539 			 * this must be an imposter
540 			 */
541 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
542 			(me, "MAIN IMPOSTER CAUGHT!\n");
543 
544 
545 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
546 			NSCD_SELF_CRED_MAIN_IMPOSTER);
547 		}
548 		break;
549 
550 	case NSCD_FORKER:
551 		if (_whoami == NSCD_FORKER || uid != forker_uid) {
552 			/*
553 			 * I'm forker, or uid from door is not correct,
554 			 * this must be an imposter
555 			 */
556 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
557 			(me, "FORKER IMPOSTER CAUGHT!\n");
558 
559 
560 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
561 			NSCD_SELF_CRED_FORKER_IMPOSTER);
562 			break;
563 		}
564 
565 		/* only main needs to know the forker */
566 		if (_whoami != NSCD_MAIN) {
567 
568 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
569 			NSCD_SELF_CRED_WRONG_NSCD);
570 			break;
571 		}
572 
573 		if (ucred_getpid(uc) != forker_pid) {
574 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
575 		(me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
576 			ucred_getpid(uc), forker_pid);
577 
578 
579 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
580 			NSCD_SELF_CRED_FORKER_IMPOSTER);
581 			break;
582 		}
583 
584 		if (n_desc < 1) {
585 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
586 			(me, "BAD FORKER, NO DOOR!\n");
587 
588 
589 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
590 			NSCD_SELF_CRED_NO_DOOR);
591 			break;
592 		}
593 
594 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
595 			dp->d_data.d_desc.d_descriptor > 0 &&
596 			dp->d_data.d_desc.d_id != 0) {
597 			(void) mutex_lock(&forking_lock);
598 			if (forking_door != -1)
599 				(void) close(forking_door);
600 			forking_door = dp->d_data.d_desc.d_descriptor;
601 			(void) mutex_unlock(&forking_lock);
602 
603 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
604 			(me, "forking door is %d\n", forking_door);
605 
606 			NSCD_SET_STATUS_SUCCESS(phdr);
607 		} else {
608 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
609 			break;
610 		}
611 
612 		/* monitor the forker nscd */
613 		(void) thr_create(NULL, 0, forker_monitor, NULL,
614 			THR_DETACHED, NULL);
615 
616 		break;
617 
618 	case NSCD_CHILD:
619 		if (_whoami != NSCD_MAIN) {
620 			/* child nscd can only talk to the main nscd */
621 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
622 			(me, "CHILD IMPOSTER CAUGHT!\n");
623 
624 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
625 			NSCD_SELF_CRED_CHILD_IMPOSTER);
626 			break;
627 		}
628 
629 		/* get the main nscd assigned slot number */
630 		ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf);
631 		cslot = ih->slot;
632 		(void) mutex_lock(&child_lock);
633 		if (cslot < 0 || cslot >= max_pu_nscd)
634 			ch = NULL;
635 		else
636 			ch = child[cslot];
637 		(void) mutex_unlock(&child_lock);
638 
639 		if (ch == NULL) {
640 			/* Bad slot number */
641 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
642 			(me, "bad slot number %d\n", cslot);
643 
644 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
645 			NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
646 			break;
647 		}
648 
649 		if (uid != ch->child_uid) {
650 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
651 		(me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
652 			uid, ch->child_uid);
653 
654 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
655 			NSCD_SELF_CRED_CHILD_IMPOSTER);
656 			break;
657 		}
658 
659 		if (ch->child_state != CHILD_STATE_UIDKNOWN &&
660 			ch->child_state != CHILD_STATE_FORKSENT) {
661 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
662 			(me, "invalid slot/child state (%d) for uid %d\n",
663 			ch->child_state, uid);
664 
665 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
666 			NSCD_SELF_CRED_INVALID_SLOT_STATE);
667 			break;
668 		}
669 
670 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
671 		(me, "d_descriptor = %d, d_id = %lld\n",
672 		dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id);
673 
674 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
675 			dp->d_data.d_desc.d_descriptor > 0 &&
676 			dp->d_data.d_desc.d_id != 0) {
677 			(void) mutex_lock(ch->mutex);
678 			if (ch->child_door != -1)
679 				(void) close(ch->child_door);
680 			ch->child_door = dp->d_data.d_desc.d_descriptor;
681 			ch->child_pid  = ucred_getpid(uc);
682 			ch->child_state  = CHILD_STATE_PIDKNOWN;
683 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
684 			(me, "child in slot %d has door %d\n",
685 				cslot, ch->child_door);
686 
687 			/*
688 			 * let waiters know that the child is ready to
689 			 * serve
690 			 */
691 			(void) cond_broadcast(ch->cond);
692 			(void) mutex_unlock(ch->mutex);
693 
694 			/* monitor the child nscd */
695 			(void) thr_create(NULL, 0, child_monitor,
696 				ch, THR_DETACHED, NULL);
697 			NSCD_SET_STATUS_SUCCESS(phdr);
698 			break;
699 		} else {
700 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
701 		}
702 		break;
703 	}
704 
705 	ucred_free(uc);
706 	uc = NULL;
707 }
708 
709 void
710 _nscd_proc_pulse(
711 	void		*buf,
712 	int		iam)
713 {
714 	long		last_active;
715 	int		done = 0;
716 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
717 	char		*me = "_nscd_proc_pulse";
718 
719 	/* only main nscd sends pulse */
720 	if (iam != NSCD_MAIN) {
721 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
722 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam);
723 
724 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
725 			NSCD_SELF_CRED_MAIN_IMPOSTER);
726 	}
727 
728 	/* forker doesn't return stats, it just pauses */
729 	if (_whoami == NSCD_FORKER) {
730 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
731 		(me, "forker ready to pause ...\n");
732 
733 		/*CONSTCOND*/
734 		while (1)
735 			(void) pause();
736 
737 		NSCD_RETURN_STATUS_SUCCESS(phdr);
738 	}
739 
740 	/* remember the current activity sequence number */
741 	(void) mutex_lock(&activity_lock);
742 	last_active = activity;
743 	(void) mutex_unlock(&activity_lock);
744 
745 	while (!done) {
746 
747 		/* allow per_user_nscd_ttl seconds of inactivity */
748 		(void) sleep(pu_nscd_ttl);
749 
750 		(void) mutex_lock(&activity_lock);
751 		if (last_active == activity)
752 			done = 1;
753 		else {
754 			last_active = activity;
755 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
756 			(me, "active, sleep again for %d seconds\n",
757 				pu_nscd_ttl);
758 		}
759 		(void) mutex_unlock(&activity_lock);
760 	}
761 
762 	/* no activity in the specified seconds, exit and disconnect */
763 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
764 	(me, "no activity in the last %d seconds, exit\n", pu_nscd_ttl);
765 	exit(0);
766 }
767 
768 void
769 _nscd_proc_fork(
770 	void		*buf,
771 	int		iam)
772 {
773 	int		slot;
774 	int		ret;
775 	char		*fmri;
776 	pid_t		cid;
777 	uid_t		set2uid;
778 	gid_t		set2gid;
779 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
780 	char		*me = "_nscd_proc_fork";
781 	nscd_fork_t	*f;
782 	nscd_imhere_t	ih;
783 
784 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
785 	(me, "%d receives fork request from %d\n", _whoami, iam);
786 
787 	/* only main nscd sends fork requests */
788 	if (iam != NSCD_MAIN) {
789 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
790 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n",
791 			iam);
792 
793 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
794 			NSCD_SELF_CRED_MAIN_IMPOSTER);
795 	}
796 
797 	/* only forker handles fork requests */
798 	if (_whoami != NSCD_FORKER) {
799 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
800 		(me, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n");
801 
802 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
803 			NSCD_SELF_CRED_WRONG_NSCD);
804 	}
805 
806 	/* fork a child for the slot assigned by the main nscd */
807 	f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf);
808 	slot = f->slot;
809 	/* set the uid/gid as assigned by the main nscd */
810 	set2uid = f->uid;
811 	set2gid = f->gid;
812 
813 	/* ignore bad slot number */
814 	if (slot < 0 || slot >= max_pu_nscd) {
815 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
816 		(me, "bas slot number\n");
817 
818 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
819 		NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
820 	}
821 
822 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
823 	(me, "before fork1() ...\n");
824 
825 	if ((cid = fork1()) == 0) {
826 		_whoami = NSCD_CHILD;
827 
828 		/* close all except the log file */
829 		if (_logfd > 0) {
830 			int i;
831 			for (i = 0; i < _logfd; i++)
832 				(void) close(i);
833 			closefrom(_logfd + 1);
834 		} else
835 			closefrom(0);
836 
837 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
838 		(me, "child %d\n", getpid());
839 
840 		(void) setgid(set2gid);
841 		(void) setuid(set2uid);
842 
843 		/* set up the door and server thread pool */
844 		if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1)
845 			exit(-1);
846 
847 		/* tell libsldap to do self cred only */
848 		(void) setup_ldap_backend();
849 
850 		/* notify main that child is active */
851 		ih.slot = slot;
852 		for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
853 			ret = _nscd_doorcall_sendfd(_doorfd,
854 				NSCD_IMHERE | (NSCD_CHILD & NSCD_WHOAMI),
855 				&ih, sizeof (ih), NULL);
856 
857 			NSCD_RETURN_STATUS_SUCCESS(phdr);
858 	} if (cid  == (pid_t)-1) {
859 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
860 		(me, "forker unable to fork ...\n");
861 
862 		/* enter the maintenance mode */
863 		if ((fmri = getenv("SMF_FMRI")) != NULL) {
864 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
865 			(me, "entering maintenance mode ...\n");
866 			smf_maintain_instance(fmri, SMF_TEMPORARY);
867 		}
868 		exit(0);
869 	} else {
870 		/*
871 		 * start the monitor so as to exit as early as
872 		 * possible if no other processes are running
873 		 * with the same PUN uid (i.e., this PUN is
874 		 * not needed any more)
875 		 */
876 		(void) init_user_proc_monitor();
877 
878 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
879 		(me, "child forked:  parent pid = %d, child pid = %d\n",
880 		getpid(), cid);
881 
882 		NSCD_SET_STATUS_SUCCESS(phdr);
883 	}
884 
885 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
886 	(me, "after fork\n");
887 }
888 
889 static void
890 selfcred_fork(
891 	void		*buf,
892 	int		doorfd,
893 	int		cslot,
894 	uid_t		uid,
895 	gid_t		gid)
896 {
897 	int		ret;
898 	nscd_fork_t	f;
899 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
900 	char		*me = "selfcred_fork";
901 
902 	/* if no door fd, do nothing */
903 	if (doorfd == -1) {
904 		NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
905 			NSCD_SELF_CRED_NO_DOOR);
906 	}
907 
908 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
909 	(me, "sending fork request to door %d for slot %d "
910 		"(uid = %d, gid = %d)\n", doorfd, cslot, uid, gid);
911 
912 	f.slot = cslot;
913 	f.uid = uid;
914 	f.gid = gid;
915 
916 	ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI),
917 		&f, sizeof (f), NULL, 0, phdr);
918 
919 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
920 	(me, "fork request sent to door %d for slot %d (rc = %d)\n",
921 		doorfd, cslot, ret);
922 
923 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
924 
925 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
926 		(me, "fork request sent to door %d for slot %d failed: "
927 		"status = %d, errno = %s, nscd status = %d\n", doorfd,
928 		cslot, NSCD_GET_STATUS(phdr), strerror(NSCD_GET_ERRNO(phdr)),
929 		NSCD_GET_NSCD_STATUS(phdr));
930 
931 	}
932 }
933 
934 void
935 _nscd_proc_alt_get(
936 	void		*buf,
937 	int		*door)
938 {
939 	int		errnum;
940 	uid_t		set2uid;
941 	gid_t		set2gid;
942 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
943 	char		*me = "_nscd_proc_alt_get";
944 	ucred_t		*uc = NULL;
945 	child_t		*ch;
946 
947 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
948 	(me, "getting an alternate door ...\n");
949 
950 	/* make sure there is a door to talk to the forker */
951 	if (forking_door == -1) {
952 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
953 		(me, "no door to talk to the forker\n");
954 
955 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
956 		NSCD_SELF_CRED_NO_FORKER);
957 	}
958 
959 	/* get door client's credential information */
960 	if (door_ucred(&uc) != 0) {
961 		errnum = errno;
962 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
963 		(me, "door_ucred failed: %s\n", strerror(errnum));
964 
965 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
966 			NSCD_DOOR_UCRED_ERROR);
967 	}
968 
969 	/* get door client's effective uid and effective gid */
970 	set2uid = ucred_geteuid(uc);
971 	set2gid = ucred_getegid(uc);
972 	ucred_free(uc);
973 	uc = NULL;
974 
975 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
976 	(me, "child uid = %d, gid = %d\n", set2uid, set2gid);
977 
978 	/* is a slot available ? if not, no one to serve */
979 	if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) {
980 
981 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
982 		(me, "no child slot available (child array = %p, slot = %d)\n",
983 			child, ch->child_slot);
984 
985 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
986 			NSCD_SELF_CRED_NO_CHILD_SLOT);
987 	}
988 
989 	/* create the per user nscd if necessary */
990 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
991 
992 		nss_pheader_t	phdr1;
993 		NSCD_CLEAR_STATUS(&phdr1);
994 
995 		(void) mutex_lock(ch->mutex);
996 		if (ch->child_state == CHILD_STATE_UIDKNOWN) {
997 
998 			/* ask forker to fork a new child */
999 			selfcred_fork(&phdr1, forking_door, ch->child_slot,
1000 				set2uid, set2gid);
1001 			if (NSCD_STATUS_IS_NOT_OK(&phdr1)) {
1002 				(void) mutex_unlock(ch->mutex);
1003 				NSCD_COPY_STATUS(phdr, &phdr1);
1004 				return;
1005 			}
1006 			ch->child_state = CHILD_STATE_FORKSENT;
1007 		}
1008 
1009 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1010 		(me, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1011 				ch->child_slot, set2uid, set2gid);
1012 
1013 		/* wait for the per user nscd to become available */
1014 		while (ch->child_state == CHILD_STATE_FORKSENT) {
1015 			timestruc_t to;
1016 			int err;
1017 			int ttl = 5;
1018 
1019 			to.tv_sec = ttl;
1020 			to.tv_nsec = 0;
1021 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1022 				(me, "cond_reltimedwait %d seconds\n", ttl);
1023 			err = cond_reltimedwait(ch->cond, ch->mutex, &to);
1024 			if (err == ETIME) {
1025 				ch->child_state =
1026 					CHILD_STATE_UIDKNOWN;
1027 				_NSCD_LOG(NSCD_LOG_SELF_CRED,
1028 					NSCD_LOG_LEVEL_DEBUG)
1029 				(me, "door wait timedout (slot = %d)\n",
1030 					ch->child_slot);
1031 				break;
1032 			}
1033 		}
1034 		(void) mutex_unlock(ch->mutex);
1035 	}
1036 
1037 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
1038 
1039 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1040 			NSCD_SELF_CRED_INVALID_SLOT_STATE);
1041 	}
1042 
1043 	*door = ch->child_door;
1044 
1045 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1046 	(me, "returning door %d for slot %d, uid %d, gid = %d\n",
1047 		*door, ch->child_slot, set2uid, set2gid);
1048 
1049 	NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0);
1050 }
1051 
1052 static char **
1053 cpargv(
1054 	int	argc,
1055 	char	**inargv)
1056 {
1057 	char	**newargv;
1058 	int	c = 4;
1059 	int	i = 0, j, k = 0, n = 0;
1060 
1061 	newargv = (char **)calloc(c + 1, sizeof (char *));
1062 	if (newargv == NULL)
1063 		return (NULL);
1064 
1065 	newargv[n] = strdup(inargv[0]);
1066 	if (newargv[n++] == NULL) {
1067 		free(newargv);
1068 		return (NULL);
1069 	}
1070 
1071 	newargv[n] = strdup("-F");
1072 	if (newargv[n++] == NULL) {
1073 		free(newargv[0]);
1074 		free(newargv);
1075 		return (NULL);
1076 	}
1077 
1078 	for (i = 1; i < argc; i++) {
1079 		if (strcmp(inargv[i], "-f") == 0)
1080 			k = 2;
1081 		if (k  == 0)
1082 			continue;
1083 
1084 		newargv[n] = strdup(inargv[i]);
1085 		if (newargv[n] == NULL) {
1086 			for (j = 0; j < n; j++)
1087 				free(newargv[j]);
1088 			free(newargv);
1089 			return (NULL);
1090 		}
1091 
1092 		k--;
1093 		n++;
1094 	}
1095 	return (newargv);
1096 }
1097 
1098 
1099 void
1100 _nscd_start_forker(
1101 	char	*path,
1102 	int	argc,
1103 	char	**argv)
1104 {
1105 	pid_t	cid;
1106 	struct	rlimit rl;
1107 	char	*me = "_nscd_start_forker";
1108 
1109 	/* if self cred is not configured, do nothing */
1110 	if (!_nscd_is_self_cred_on(1, NULL))
1111 		return;
1112 
1113 	/* save pathname and generate the new argv for the forker */
1114 	execpath = strdup(path);
1115 	execargv = cpargv(argc, argv);
1116 	if (execpath == NULL || execargv == NULL)
1117 		exit(1);
1118 
1119 	switch (cid = fork1()) {
1120 		case (pid_t)-1:
1121 			exit(1);
1122 			break;
1123 		case 0:
1124 			/* start the forker nscd */
1125 			(void) execv(path, execargv);
1126 			exit(0);
1127 			break;
1128 		default:
1129 			/* main nscd */
1130 			/* remember process id of the forker */
1131 			forker_pid = cid;
1132 
1133 			/* set NOFILE to unlimited */
1134 			rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1135 			if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1136 				_NSCD_LOG(NSCD_LOG_SELF_CRED,
1137 					NSCD_LOG_LEVEL_ERROR)
1138 				(me, "Cannot set open file limit: %s\n",
1139 					strerror(errno));
1140 				exit(1);
1141 			}
1142 
1143 			/* enable child nscd management */
1144 			(void) _nscd_init_cslots();
1145 			break;
1146 	}
1147 }
1148 
1149 static nscd_rc_t
1150 get_ldap_funcs(
1151 	char			*name,
1152 	void			**func_p)
1153 {
1154 	char			*me = "get_ldap_funcs";
1155 	static void		*handle = NULL;
1156 	void			*sym;
1157 
1158 	if (name == NULL && handle != NULL) {
1159 		(void) dlclose(handle);
1160 		return (NSCD_SUCCESS);
1161 	}
1162 	/* no handle to close, it's OK */
1163 	if (name == NULL)
1164 		return (NSCD_SUCCESS);
1165 
1166 	if (handle == NULL) {
1167 		handle = dlopen("libsldap.so.1", RTLD_LAZY);
1168 		if (handle == NULL) {
1169 
1170 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1171 			(me, "unable to dlopen libsldap.so.1");
1172 			return (NSCD_CFG_DLOPEN_ERROR);
1173 		}
1174 	}
1175 
1176 	if ((sym = dlsym(handle, name)) == NULL) {
1177 
1178 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1179 			(me, "unable to find symbol %s", name);
1180 			return (NSCD_CFG_DLSYM_ERROR);
1181 	} else
1182 		(void) memcpy(func_p, &sym, sizeof (void *));
1183 
1184 	return (NSCD_SUCCESS);
1185 }
1186 
1187 
1188 int
1189 _nscd_is_self_cred_on(int recheck, char **dblist)
1190 {
1191 	static int	checked = 0;
1192 	static int	is_on = 0;
1193 	static int	(*ldap_func)();
1194 	char		*srcs = "ldap"; /* only ldap support self cred */
1195 	int		ldap_on = 0;
1196 
1197 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_config";
1198 	ns_ldap_self_gssapi_config_t ldap_config;
1199 
1200 	if (checked && !recheck) {
1201 		if (is_on && dblist != NULL)
1202 			*dblist = selfcred_dbs;
1203 		return (is_on);
1204 	}
1205 
1206 	if (selfcred_dbs != NULL)
1207 		free(selfcred_dbs);
1208 	selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs);
1209 
1210 	/*
1211 	 * also check the ldap backend to see if
1212 	 * the configuration there is good for
1213 	 * doing self credentialing
1214 	 */
1215 	if (ldap_func == NULL)
1216 		(void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1217 	if (ldap_func != NULL) {
1218 		if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS &&
1219 			ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
1220 			ldap_on = 1;
1221 	}
1222 
1223 	is_on = pu_nscd_enabled == nscd_true &&
1224 			ldap_on && selfcred_dbs != NULL;
1225 
1226 	checked = 1;
1227 
1228 	if (is_on && dblist != NULL)
1229 		*dblist = selfcred_dbs;
1230 
1231 	return (is_on);
1232 }
1233 
1234 static nscd_rc_t
1235 setup_ldap_backend()
1236 {
1237 	nscd_rc_t	rc;
1238 	static void	(*ldap_func)();
1239 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_only_set";
1240 	if (ldap_func == NULL)
1241 		rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1242 	if (ldap_func != NULL) {
1243 		ldap_func(1);
1244 		return (NSCD_SUCCESS);
1245 	}
1246 	return (rc);
1247 }
1248 
1249 /*ARGSUSED*/
1250 void
1251 _nscd_peruser_getadmin(
1252 	void		*buf,
1253 	int		buf_size)
1254 {
1255 	void		*result_mn = NSCD_N2N_DOOR_DATA(void, buf);
1256 	int		errnum = 0;
1257 	int		ret;
1258 	uid_t		uid;
1259 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
1260 	char		*me = "_nscd_peruser_getadmin";
1261 	ucred_t		*uc = NULL;
1262 	child_t		*ch;
1263 
1264 	/* get door client's credential information */
1265 	if (door_ucred(&uc) != 0) {
1266 		errnum = errno;
1267 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1268 		(me, "door_ucred failed: %s\n", strerror(errnum));
1269 
1270 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
1271 			NSCD_DOOR_UCRED_ERROR);
1272 	}
1273 
1274 	/* get door client's effective uid */
1275 	uid = ucred_geteuid(uc);
1276 	ucred_free(uc);
1277 	uc = NULL;
1278 
1279 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1280 	(me, "per user get admin ... (uid = %d)\n", uid);
1281 
1282 	/* is the per-user nscd running ? if not, no one to serve */
1283 	ch = get_cslot(uid, 1);
1284 	if (ch == NULL) {
1285 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1286 			NSCD_SELF_CRED_NO_CHILD_SLOT);
1287 	}
1288 
1289 	ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN,
1290 		NULL, sizeof (nscd_admin_t), result_mn,
1291 		sizeof (nscd_admin_t), phdr);
1292 
1293 	if (ret == NSS_SUCCESS) {
1294 		phdr->data_len = sizeof (nscd_admin_t);
1295 		return;
1296 	}
1297 }
1298 
1299 static void
1300 set_selfcred_cfg(
1301 	char	param,
1302 	void	*data)
1303 {
1304 	int64_t	prop_int;
1305 	char	*me = "set_selfcred_cfg";
1306 
1307 	if (param == 'a' || param == 'e') {
1308 		pu_nscd_enabled = *(uint8_t *)get_smf_prop(
1309 			"enable_per_user_lookup", 'b', data);
1310 
1311 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1312 		(me, "self cred config: enabled = %d\n", pu_nscd_enabled);
1313 	}
1314 
1315 	if (param == 'a' || param == 't') {
1316 		prop_int = *(int *)data;
1317 		pu_nscd_ttl = *(int64_t *)get_smf_prop(
1318 			"per_user_nscd_time_to_live", 'i', &prop_int);
1319 
1320 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1321 		(me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl);
1322 	}
1323 }
1324 
1325 /* ARGSUSED */
1326 nscd_rc_t
1327 _nscd_cfg_selfcred_notify(
1328 	void				*data,
1329 	struct nscd_cfg_param_desc	*pdesc,
1330 	nscd_cfg_id_t			*nswdb,
1331 	nscd_cfg_flag_t			dflag,
1332 	nscd_cfg_error_t		**errorp,
1333 	void				*cookie)
1334 {
1335 
1336 	nscd_cfg_global_selfcred_t	*sc_cfg = &nscd_selfcred_cfg_g;
1337 	int				off;
1338 
1339 	/*
1340 	 * At init time, the whole group of config params are received.
1341 	 * At update time, group or individual parameter value could
1342 	 * be received.
1343 	 */
1344 
1345 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1346 
1347 		*sc_cfg = *(nscd_cfg_global_selfcred_t *)data;
1348 
1349 		off = offsetof(nscd_cfg_global_selfcred_t,
1350 			enable_selfcred);
1351 		set_selfcred_cfg('e', (char *)data + off);
1352 
1353 		off = offsetof(nscd_cfg_global_selfcred_t,
1354 			max_per_user_nscd);
1355 		set_selfcred_cfg('n', (char *)data + off);
1356 
1357 		off = offsetof(nscd_cfg_global_selfcred_t,
1358 			per_user_nscd_ttl);
1359 		set_selfcred_cfg('t', (char *)data + off);
1360 
1361 		return (NSCD_SUCCESS);
1362 	}
1363 
1364 	/*
1365 	 * individual config parameter
1366 	 */
1367 	off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred);
1368 	if (pdesc->p_offset == off) {
1369 		sc_cfg->enable_selfcred = *(nscd_bool_t *)data;
1370 		set_selfcred_cfg('e', data);
1371 		return (NSCD_SUCCESS);
1372 	}
1373 
1374 	off = offsetof(nscd_cfg_global_selfcred_t, max_per_user_nscd);
1375 	if (pdesc->p_offset == off) {
1376 		sc_cfg->max_per_user_nscd = *(int *)data;
1377 		set_selfcred_cfg('n', data);
1378 		return (NSCD_SUCCESS);
1379 	}
1380 
1381 	off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl);
1382 	if (pdesc->p_offset == off) {
1383 		sc_cfg->per_user_nscd_ttl = *(int *)data;
1384 		set_selfcred_cfg('t', data);
1385 		return (NSCD_SUCCESS);
1386 	}
1387 
1388 	return (NSCD_SUCCESS);
1389 }
1390 
1391 /* ARGSUSED */
1392 nscd_rc_t
1393 _nscd_cfg_selfcred_verify(
1394 	void				*data,
1395 	struct	nscd_cfg_param_desc	*pdesc,
1396 	nscd_cfg_id_t			*nswdb,
1397 	nscd_cfg_flag_t			dflag,
1398 	nscd_cfg_error_t		**errorp,
1399 	void				**cookie)
1400 {
1401 
1402 	return (NSCD_SUCCESS);
1403 }
1404 
1405 /* ARGSUSED */
1406 nscd_rc_t
1407 _nscd_cfg_selfcred_get_stat(
1408 	void				**stat,
1409 	struct nscd_cfg_stat_desc	*sdesc,
1410 	nscd_cfg_id_t			*nswdb,
1411 	nscd_cfg_flag_t			*dflag,
1412 	void				(**free_stat)(void *stat),
1413 	nscd_cfg_error_t		**errorp)
1414 {
1415 	return (NSCD_SUCCESS);
1416 }
1417 
1418 static int
1419 check_uid(char *pid_name)
1420 {
1421 	char		pname[PATH_MAX];
1422 	static pid_t	pid = 0;
1423 	static uid_t	uid = 0;
1424 	static uid_t	euid = 0;
1425 	int		pfd; /* file descriptor for /proc/<pid>/psinfo */
1426 	psinfo_t 	info;  /* process information from /proc */
1427 
1428 	if (uid == 0)  {
1429 		pid = getpid();
1430 		uid = getuid();
1431 		euid = geteuid();
1432 	}
1433 
1434 	(void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name);
1435 retry:
1436 	if ((pfd = open(pname, O_RDONLY)) == -1) {
1437 		/* Process may have exited */
1438 			return (1);
1439 	}
1440 
1441 	/*
1442 	 * Get the info structure for the process and close quickly.
1443 	 */
1444 	if (read(pfd, (char *)&info, sizeof (info)) < 0) {
1445 		int	saverr = errno;
1446 
1447 		(void) close(pfd);
1448 		if (saverr == EAGAIN)
1449 			goto retry;
1450 		if (saverr != ENOENT)
1451 			return (1);
1452 	}
1453 	(void) close(pfd);
1454 
1455 	if (info.pr_pid != pid &&
1456 		info.pr_uid == uid && info.pr_euid == euid)
1457 		return (0);
1458 	else
1459 		return (1);
1460 }
1461 
1462 
1463 /*
1464  * FUNCTION: check_user_process
1465  */
1466 /*ARGSUSED*/
1467 static void *
1468 check_user_process(void *arg)
1469 {
1470 
1471 	DIR		*dp;
1472 	struct dirent	*ep;
1473 	int		found;
1474 	char		*me = "check_user_process";
1475 
1476 	/*CONSTCOND*/
1477 	while (1) {
1478 		(void) sleep(60);
1479 
1480 		found = 0;
1481 
1482 		/*
1483 		 * search the /proc directory and look at each process
1484 		 */
1485 		if ((dp = opendir("/proc")) == NULL) {
1486 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1487 			(me, "unable to open the /proc directory\n");
1488 			continue;
1489 		}
1490 
1491 		/* for each active process */
1492 		while (ep = readdir(dp)) {
1493 			if (ep->d_name[0] == '.')    /* skip . and .. */
1494 				continue;
1495 			if (check_uid(ep->d_name) == 0) {
1496 				found = 1;
1497 				break;
1498 			}
1499 		}
1500 
1501 		/*
1502 		 * if no process running as the PUN uid found, exit
1503 		 * to kill this PUN
1504 		 */
1505 		if (found == 0) {
1506 			(void) closedir(dp);
1507 			exit(1);
1508 		}
1509 		(void) closedir(dp);
1510 	}
1511 	/* NOTREACHED */
1512 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1513 }
1514 
1515 static nscd_rc_t
1516 init_user_proc_monitor() {
1517 
1518 	int	errnum;
1519 	char	*me = "init_user_proc_monitor";
1520 
1521 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1522 	(me, "initializing the user process monitor\n");
1523 
1524 	/*
1525 	 * start a thread to make sure there is at least a process
1526 	 * running as the PUN user. If not, terminate this PUN.
1527 	 */
1528 	if (thr_create(NULL, NULL, check_user_process,
1529 		NULL, THR_DETACHED, NULL) != 0) {
1530 		errnum = errno;
1531 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1532 		(me, "thr_create: %s\n", strerror(errnum));
1533 		return (NSCD_THREAD_CREATE_ERROR);
1534 	}
1535 
1536 	return (NSCD_SUCCESS);
1537 }
1538 
1539 static void *
1540 get_smf_prop(const char *var, char type, void *def_val)
1541 {
1542 	scf_simple_prop_t	*prop;
1543 	void			*val = def_val;
1544 	char			*me = "get_smf_prop";
1545 
1546 	prop = scf_simple_prop_get(NULL, NULL, "config", var);
1547 	if (prop) {
1548 		switch (type) {
1549 		case 'b':
1550 			val = scf_simple_prop_next_boolean(prop);
1551 			break;
1552 
1553 		case 'i':
1554 			val = scf_simple_prop_next_integer(prop);
1555 			break;
1556 
1557 		case 'c':
1558 			val = scf_simple_prop_next_count(prop);
1559 			break;
1560 		}
1561 		scf_simple_prop_free(prop);
1562 	}
1563 
1564 	if (prop == NULL || val == NULL) {
1565 		char	vs[64];
1566 
1567 		switch (type) {
1568 		case 'b':
1569 			if (*(uint8_t *)def_val)
1570 				(void) strcpy(vs, "yes");
1571 			else
1572 				(void) strcpy(vs, "no");
1573 
1574 			break;
1575 
1576 		case 'i':
1577 		case 'c':
1578 			(void) sprintf(vs, "%lld", *(int64_t *)def_val);
1579 			break;
1580 
1581 		}
1582 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT)
1583 		(me, "no value for config/%s (%s). "
1584 			"Using default \"%s\"\n", var,
1585 			scf_strerror(scf_error()), vs);
1586 	}
1587 
1588 	return (val);
1589 }
1590