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