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