xref: /illumos-gate/usr/src/cmd/nscd/nscd_selfcred.c (revision 5951ced0ac070feedc4707fba3149df0b5b406f8)
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_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
524 		    NSCD_DOOR_UCRED_ERROR);
525 	}
526 	uid = ucred_geteuid(uc);
527 
528 	switch (iam) {
529 
530 	case NSCD_MAIN:
531 		if (_whoami == NSCD_MAIN || uid != main_uid) {
532 			/*
533 			 * I'm main, or uid from door is not correct,
534 			 * this must be an imposter
535 			 */
536 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
537 			(me, "MAIN IMPOSTER CAUGHT!\n");
538 
539 
540 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
541 			    NSCD_SELF_CRED_MAIN_IMPOSTER);
542 		}
543 		break;
544 
545 	case NSCD_FORKER:
546 		if (_whoami == NSCD_FORKER || uid != forker_uid) {
547 			/*
548 			 * I'm forker, or uid from door is not correct,
549 			 * this must be an imposter
550 			 */
551 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
552 			(me, "FORKER IMPOSTER CAUGHT!\n");
553 
554 
555 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
556 			    NSCD_SELF_CRED_FORKER_IMPOSTER);
557 			break;
558 		}
559 
560 		/* only main needs to know the forker */
561 		if (_whoami != NSCD_MAIN) {
562 
563 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
564 			    NSCD_SELF_CRED_WRONG_NSCD);
565 			break;
566 		}
567 
568 		if (ucred_getpid(uc) != forker_pid) {
569 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
570 			(me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
571 			    ucred_getpid(uc), forker_pid);
572 
573 
574 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
575 			    NSCD_SELF_CRED_FORKER_IMPOSTER);
576 			break;
577 		}
578 
579 		if (n_desc < 1) {
580 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
581 			(me, "BAD FORKER, NO DOOR!\n");
582 
583 
584 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
585 			    NSCD_SELF_CRED_NO_DOOR);
586 			break;
587 		}
588 
589 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
590 		    dp->d_data.d_desc.d_descriptor > 0 &&
591 		    dp->d_data.d_desc.d_id != 0) {
592 			(void) mutex_lock(&forking_lock);
593 			if (forking_door != -1)
594 				(void) close(forking_door);
595 			forking_door = dp->d_data.d_desc.d_descriptor;
596 			(void) mutex_unlock(&forking_lock);
597 
598 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
599 			(me, "forking door is %d\n", forking_door);
600 
601 			NSCD_SET_STATUS_SUCCESS(phdr);
602 		} else {
603 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
604 			break;
605 		}
606 
607 		/* monitor the forker nscd */
608 		(void) thr_create(NULL, 0, forker_monitor, NULL,
609 		    THR_DETACHED, NULL);
610 
611 		break;
612 
613 	case NSCD_CHILD:
614 		if (_whoami != NSCD_MAIN) {
615 			/* child nscd can only talk to the main nscd */
616 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
617 			(me, "CHILD IMPOSTER CAUGHT!\n");
618 
619 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
620 			    NSCD_SELF_CRED_CHILD_IMPOSTER);
621 			break;
622 		}
623 
624 		/* get the main nscd assigned slot number */
625 		ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf);
626 		cslot = ih->slot;
627 		(void) mutex_lock(&child_lock);
628 		if (cslot < 0 || cslot >= max_pu_nscd)
629 			ch = NULL;
630 		else
631 			ch = child[cslot];
632 		(void) mutex_unlock(&child_lock);
633 
634 		if (ch == NULL) {
635 			/* Bad slot number */
636 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
637 			(me, "bad slot number %d\n", cslot);
638 
639 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
640 			    NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
641 			break;
642 		}
643 
644 		if (uid != ch->child_uid) {
645 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
646 		(me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
647 		    uid, ch->child_uid);
648 
649 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
650 			    NSCD_SELF_CRED_CHILD_IMPOSTER);
651 			break;
652 		}
653 
654 		if (ch->child_state != CHILD_STATE_UIDKNOWN &&
655 		    ch->child_state != CHILD_STATE_FORKSENT) {
656 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
657 			(me, "invalid slot/child state (%d) for uid %d\n",
658 			    ch->child_state, uid);
659 
660 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
661 			    NSCD_SELF_CRED_INVALID_SLOT_STATE);
662 			break;
663 		}
664 
665 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
666 		(me, "d_descriptor = %d, d_id = %lld\n",
667 		    dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id);
668 
669 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
670 		    dp->d_data.d_desc.d_descriptor > 0 &&
671 		    dp->d_data.d_desc.d_id != 0) {
672 			(void) mutex_lock(ch->mutex);
673 			if (ch->child_door != -1)
674 				(void) close(ch->child_door);
675 			ch->child_door = dp->d_data.d_desc.d_descriptor;
676 			ch->child_pid  = ucred_getpid(uc);
677 			ch->child_state  = CHILD_STATE_PIDKNOWN;
678 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
679 			(me, "child in slot %d has door %d\n",
680 			    cslot, ch->child_door);
681 
682 			/*
683 			 * let waiters know that the child is ready to
684 			 * serve
685 			 */
686 			(void) cond_broadcast(ch->cond);
687 			(void) mutex_unlock(ch->mutex);
688 
689 			/* monitor the child nscd */
690 			(void) thr_create(NULL, 0, child_monitor,
691 			    ch, THR_DETACHED, NULL);
692 			NSCD_SET_STATUS_SUCCESS(phdr);
693 			break;
694 		} else {
695 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
696 		}
697 		break;
698 	}
699 
700 	ucred_free(uc);
701 	uc = NULL;
702 }
703 
704 void
705 _nscd_proc_pulse(
706 	void		*buf,
707 	int		iam)
708 {
709 	long		last_active;
710 	int		done = 0;
711 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
712 	char		*me = "_nscd_proc_pulse";
713 
714 	/* only main nscd sends pulse */
715 	if (iam != NSCD_MAIN) {
716 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
717 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam);
718 
719 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
720 		    NSCD_SELF_CRED_MAIN_IMPOSTER);
721 	}
722 
723 	/* forker doesn't return stats, it just pauses */
724 	if (_whoami == NSCD_FORKER) {
725 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
726 		(me, "forker ready to pause ...\n");
727 
728 		/*CONSTCOND*/
729 		while (1)
730 			(void) pause();
731 
732 		NSCD_RETURN_STATUS_SUCCESS(phdr);
733 	}
734 
735 	/* remember the current activity sequence number */
736 	(void) mutex_lock(&activity_lock);
737 	last_active = activity;
738 	(void) mutex_unlock(&activity_lock);
739 
740 	while (!done) {
741 
742 		/* allow per_user_nscd_ttl seconds of inactivity */
743 		(void) sleep(pu_nscd_ttl);
744 
745 		(void) mutex_lock(&activity_lock);
746 		if (last_active == activity)
747 			done = 1;
748 		else {
749 			last_active = activity;
750 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
751 			(me, "active, sleep again for %d seconds\n",
752 			    pu_nscd_ttl);
753 		}
754 		(void) mutex_unlock(&activity_lock);
755 	}
756 
757 	/* no activity in the specified seconds, exit and disconnect */
758 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
759 	(me, "no activity in the last %d seconds, exit\n", pu_nscd_ttl);
760 	exit(0);
761 }
762 
763 void
764 _nscd_proc_fork(
765 	void		*buf,
766 	int		iam)
767 {
768 	int		slot;
769 	int		ret;
770 	char		*fmri;
771 	pid_t		cid;
772 	uid_t		set2uid;
773 	gid_t		set2gid;
774 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
775 	char		*me = "_nscd_proc_fork";
776 	nscd_fork_t	*f;
777 	nscd_imhere_t	ih;
778 
779 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
780 	(me, "%d receives fork request from %d\n", _whoami, iam);
781 
782 	/* only main nscd sends fork requests */
783 	if (iam != NSCD_MAIN) {
784 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
785 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam);
786 
787 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
788 		    NSCD_SELF_CRED_MAIN_IMPOSTER);
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_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
797 		    NSCD_SELF_CRED_WRONG_NSCD);
798 	}
799 
800 	/* fork a child for the slot assigned by the main nscd */
801 	f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf);
802 	slot = f->slot;
803 	/* set the uid/gid as assigned by the main nscd */
804 	set2uid = f->uid;
805 	set2gid = f->gid;
806 
807 	/* ignore bad slot number */
808 	if (slot < 0 || slot >= max_pu_nscd) {
809 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
810 		(me, "bas slot number\n");
811 
812 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
813 		    NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
814 	}
815 
816 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
817 	(me, "before fork1() ...\n");
818 
819 	if ((cid = fork1()) == 0) {
820 		_whoami = NSCD_CHILD;
821 
822 		/*
823 		 * remember when this child nscd starts
824 		 * (replace the forker start time)
825 		 */
826 		_nscd_set_start_time(1);
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 			(void) 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),
929 		    strerror(NSCD_GET_ERRNO(phdr)),
930 		    NSCD_GET_NSCD_STATUS(phdr));
931 
932 	}
933 }
934 
935 void
936 _nscd_proc_alt_get(
937 	void		*buf,
938 	int		*door)
939 {
940 	int		errnum;
941 	uid_t		set2uid;
942 	gid_t		set2gid;
943 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
944 	char		*me = "_nscd_proc_alt_get";
945 	ucred_t		*uc = NULL;
946 	child_t		*ch;
947 
948 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
949 	(me, "getting an alternate door ...\n");
950 
951 	/* make sure there is a door to talk to the forker */
952 	if (forking_door == -1) {
953 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
954 		(me, "no door to talk to the forker\n");
955 
956 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
957 		    NSCD_SELF_CRED_NO_FORKER);
958 	}
959 
960 	/* get door client's credential information */
961 	if (door_ucred(&uc) != 0) {
962 		errnum = errno;
963 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
964 		(me, "door_ucred failed: %s\n", strerror(errnum));
965 
966 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
967 		    NSCD_DOOR_UCRED_ERROR);
968 	}
969 
970 	/* get door client's effective uid and effective gid */
971 	set2uid = ucred_geteuid(uc);
972 	set2gid = ucred_getegid(uc);
973 	ucred_free(uc);
974 	uc = NULL;
975 
976 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
977 	(me, "child uid = %d, gid = %d\n", set2uid, set2gid);
978 
979 	/* is a slot available ? if not, no one to serve */
980 	if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) {
981 
982 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
983 		(me, "no child slot available (child array = %p, slot = %d)\n",
984 		    child, ch->child_slot);
985 
986 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
987 		    NSCD_SELF_CRED_NO_CHILD_SLOT);
988 	}
989 
990 	/* create the per user nscd if necessary */
991 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
992 
993 		nss_pheader_t	phdr1;
994 		NSCD_CLEAR_STATUS(&phdr1);
995 
996 		(void) mutex_lock(ch->mutex);
997 		if (ch->child_state == CHILD_STATE_UIDKNOWN) {
998 
999 			/* ask forker to fork a new child */
1000 			selfcred_fork(&phdr1, forking_door, ch->child_slot,
1001 			    set2uid, set2gid);
1002 			if (NSCD_STATUS_IS_NOT_OK(&phdr1)) {
1003 				(void) mutex_unlock(ch->mutex);
1004 				NSCD_COPY_STATUS(phdr, &phdr1);
1005 				return;
1006 			}
1007 			ch->child_state = CHILD_STATE_FORKSENT;
1008 		}
1009 
1010 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1011 		(me, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1012 		    ch->child_slot, set2uid, set2gid);
1013 
1014 		/* wait for the per user nscd to become available */
1015 		while (ch->child_state == CHILD_STATE_FORKSENT) {
1016 			timestruc_t to;
1017 			int err;
1018 			int ttl = 5;
1019 
1020 			to.tv_sec = ttl;
1021 			to.tv_nsec = 0;
1022 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1023 				(me, "cond_reltimedwait %d seconds\n", ttl);
1024 			err = cond_reltimedwait(ch->cond, ch->mutex, &to);
1025 			if (err == ETIME) {
1026 				ch->child_state = 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 
1107 	/* if self cred is not configured, do nothing */
1108 	if (!_nscd_is_self_cred_on(1, NULL))
1109 		return;
1110 
1111 	/* save pathname and generate the new argv for the forker */
1112 	execpath = strdup(path);
1113 	execargv = cpargv(argc, argv);
1114 	if (execpath == NULL || execargv == NULL)
1115 		exit(1);
1116 
1117 	switch (cid = fork1()) {
1118 		case (pid_t)-1:
1119 			exit(1);
1120 			break;
1121 		case 0:
1122 			/* start the forker nscd */
1123 			(void) execv(path, execargv);
1124 			exit(0);
1125 			break;
1126 		default:
1127 			/* main nscd */
1128 			/* remember process id of the forker */
1129 			forker_pid = cid;
1130 
1131 			/* enable child nscd management */
1132 			(void) _nscd_init_cslots();
1133 			break;
1134 	}
1135 }
1136 
1137 static nscd_rc_t
1138 get_ldap_funcs(
1139 	char			*name,
1140 	void			**func_p)
1141 {
1142 	char			*me = "get_ldap_funcs";
1143 	static void		*handle = NULL;
1144 	void			*sym;
1145 
1146 	if (name == NULL && handle != NULL) {
1147 		(void) dlclose(handle);
1148 		return (NSCD_SUCCESS);
1149 	}
1150 	/* no handle to close, it's OK */
1151 	if (name == NULL)
1152 		return (NSCD_SUCCESS);
1153 
1154 	if (handle == NULL) {
1155 		handle = dlopen("libsldap.so.1", RTLD_LAZY);
1156 		if (handle == NULL) {
1157 
1158 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1159 			(me, "unable to dlopen libsldap.so.1");
1160 			return (NSCD_CFG_DLOPEN_ERROR);
1161 		}
1162 	}
1163 
1164 	if ((sym = dlsym(handle, name)) == NULL) {
1165 
1166 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1167 			(me, "unable to find symbol %s", name);
1168 			return (NSCD_CFG_DLSYM_ERROR);
1169 	} else
1170 		(void) memcpy(func_p, &sym, sizeof (void *));
1171 
1172 	return (NSCD_SUCCESS);
1173 }
1174 
1175 
1176 int
1177 _nscd_is_self_cred_on(int recheck, char **dblist)
1178 {
1179 	static int	checked = 0;
1180 	static int	is_on = 0;
1181 	static int	(*ldap_func)();
1182 	char		*srcs = "ldap"; /* only ldap support self cred */
1183 	int		ldap_on = 0;
1184 
1185 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_config";
1186 	ns_ldap_self_gssapi_config_t ldap_config;
1187 
1188 	if (checked && !recheck) {
1189 		if (is_on && dblist != NULL)
1190 			*dblist = selfcred_dbs;
1191 		return (is_on);
1192 	}
1193 
1194 	if (selfcred_dbs != NULL)
1195 		free(selfcred_dbs);
1196 	selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs);
1197 
1198 	if (selfcred_dbs == NULL) {
1199 		is_on =  0;
1200 		checked = 1;
1201 		return (0);
1202 	}
1203 
1204 	/*
1205 	 * also check the ldap backend to see if
1206 	 * the configuration there is good for
1207 	 * doing self credentialing
1208 	 */
1209 	if (ldap_func == NULL)
1210 		(void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1211 	if (ldap_func != NULL) {
1212 		if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS &&
1213 		    ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
1214 			ldap_on = 1;
1215 	}
1216 
1217 	is_on = (pu_nscd_enabled == nscd_true) && ldap_on;
1218 
1219 	checked = 1;
1220 
1221 	if (is_on && dblist != NULL)
1222 		*dblist = selfcred_dbs;
1223 
1224 	return (is_on);
1225 }
1226 
1227 static nscd_rc_t
1228 setup_ldap_backend()
1229 {
1230 	nscd_rc_t	rc;
1231 	static void	(*ldap_func)();
1232 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_only_set";
1233 	if (ldap_func == NULL)
1234 		rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1235 	if (ldap_func != NULL) {
1236 		ldap_func(1);
1237 		return (NSCD_SUCCESS);
1238 	}
1239 	return (rc);
1240 }
1241 
1242 /*ARGSUSED*/
1243 void
1244 _nscd_peruser_getadmin(
1245 	void		*buf,
1246 	int		buf_size)
1247 {
1248 	void		*result_mn = NSCD_N2N_DOOR_DATA(void, buf);
1249 	int		errnum = 0;
1250 	int		ret;
1251 	uid_t		uid;
1252 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
1253 	char		*me = "_nscd_peruser_getadmin";
1254 	ucred_t		*uc = NULL;
1255 	child_t		*ch;
1256 
1257 	/* get door client's credential information */
1258 	if (door_ucred(&uc) != 0) {
1259 		errnum = errno;
1260 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1261 		(me, "door_ucred failed: %s\n", strerror(errnum));
1262 
1263 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
1264 		    NSCD_DOOR_UCRED_ERROR);
1265 	}
1266 
1267 	/* get door client's effective uid */
1268 	uid = ucred_geteuid(uc);
1269 	ucred_free(uc);
1270 	uc = NULL;
1271 
1272 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1273 	(me, "per user get admin ... (uid = %d)\n", uid);
1274 
1275 	/* is the per-user nscd running ? if not, no one to serve */
1276 	ch = get_cslot(uid, 1);
1277 	if (ch == NULL) {
1278 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1279 		    NSCD_SELF_CRED_NO_CHILD_SLOT);
1280 	}
1281 
1282 	ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN,
1283 	    NULL, sizeof (nscd_admin_t), result_mn,
1284 	    sizeof (nscd_admin_t), phdr);
1285 
1286 	if (ret == NSS_SUCCESS) {
1287 		phdr->data_len = sizeof (nscd_admin_t);
1288 		return;
1289 	}
1290 }
1291 
1292 static void
1293 set_selfcred_cfg(
1294 	char	param,
1295 	void	*data)
1296 {
1297 	int64_t	prop_int;
1298 	uint8_t prop_boolean;
1299 	char	*me = "set_selfcred_cfg";
1300 
1301 	if (param == 'e') {
1302 		prop_boolean = *(uint8_t *)data;
1303 		pu_nscd_enabled = *(uint8_t *)get_smf_prop(
1304 		    "enable_per_user_lookup", 'b', &prop_boolean);
1305 
1306 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1307 		(me, "self cred config: enabled = %d\n", pu_nscd_enabled);
1308 	}
1309 
1310 	if (param == 't') {
1311 		prop_int = *(int *)data;
1312 		pu_nscd_ttl = *(int64_t *)get_smf_prop(
1313 		    "per_user_nscd_time_to_live", 'i', &prop_int);
1314 
1315 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1316 		(me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl);
1317 	}
1318 }
1319 
1320 /* ARGSUSED */
1321 nscd_rc_t
1322 _nscd_cfg_selfcred_notify(
1323 	void				*data,
1324 	struct nscd_cfg_param_desc	*pdesc,
1325 	nscd_cfg_id_t			*nswdb,
1326 	nscd_cfg_flag_t			dflag,
1327 	nscd_cfg_error_t		**errorp,
1328 	void				*cookie)
1329 {
1330 
1331 	nscd_cfg_global_selfcred_t	*sc_cfg = &nscd_selfcred_cfg_g;
1332 	int				off;
1333 
1334 	/*
1335 	 * At init time, the whole group of config params are received.
1336 	 * At update time, group or individual parameter value could
1337 	 * be received.
1338 	 */
1339 
1340 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1341 
1342 		*sc_cfg = *(nscd_cfg_global_selfcred_t *)data;
1343 
1344 		off = offsetof(nscd_cfg_global_selfcred_t,
1345 		    enable_selfcred);
1346 		set_selfcred_cfg('e', (char *)data + off);
1347 
1348 		off = offsetof(nscd_cfg_global_selfcred_t,
1349 		    per_user_nscd_ttl);
1350 		set_selfcred_cfg('t', (char *)data + off);
1351 
1352 		return (NSCD_SUCCESS);
1353 	}
1354 
1355 	/*
1356 	 * individual config parameter
1357 	 */
1358 	off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred);
1359 	if (pdesc->p_offset == off) {
1360 		sc_cfg->enable_selfcred = *(nscd_bool_t *)data;
1361 		set_selfcred_cfg('e', data);
1362 		return (NSCD_SUCCESS);
1363 	}
1364 
1365 	off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl);
1366 	if (pdesc->p_offset == off) {
1367 		sc_cfg->per_user_nscd_ttl = *(int *)data;
1368 		set_selfcred_cfg('t', data);
1369 		return (NSCD_SUCCESS);
1370 	}
1371 
1372 	return (NSCD_SUCCESS);
1373 }
1374 
1375 /* ARGSUSED */
1376 nscd_rc_t
1377 _nscd_cfg_selfcred_verify(
1378 	void				*data,
1379 	struct	nscd_cfg_param_desc	*pdesc,
1380 	nscd_cfg_id_t			*nswdb,
1381 	nscd_cfg_flag_t			dflag,
1382 	nscd_cfg_error_t		**errorp,
1383 	void				**cookie)
1384 {
1385 
1386 	return (NSCD_SUCCESS);
1387 }
1388 
1389 /* ARGSUSED */
1390 nscd_rc_t
1391 _nscd_cfg_selfcred_get_stat(
1392 	void				**stat,
1393 	struct nscd_cfg_stat_desc	*sdesc,
1394 	nscd_cfg_id_t			*nswdb,
1395 	nscd_cfg_flag_t			*dflag,
1396 	void				(**free_stat)(void *stat),
1397 	nscd_cfg_error_t		**errorp)
1398 {
1399 	return (NSCD_SUCCESS);
1400 }
1401 
1402 static int
1403 check_uid(char *pid_name)
1404 {
1405 	char		pname[PATH_MAX];
1406 	static pid_t	pid = 0;
1407 	static uid_t	uid = 0;
1408 	static uid_t	euid = 0;
1409 	int		pfd; /* file descriptor for /proc/<pid>/psinfo */
1410 	psinfo_t 	info;  /* process information from /proc */
1411 
1412 	if (uid == 0)  {
1413 		pid = getpid();
1414 		uid = getuid();
1415 		euid = geteuid();
1416 	}
1417 
1418 	(void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name);
1419 retry:
1420 	if ((pfd = open(pname, O_RDONLY)) == -1) {
1421 		/* Process may have exited */
1422 			return (1);
1423 	}
1424 
1425 	/*
1426 	 * Get the info structure for the process and close quickly.
1427 	 */
1428 	if (read(pfd, (char *)&info, sizeof (info)) < 0) {
1429 		int	saverr = errno;
1430 
1431 		(void) close(pfd);
1432 		if (saverr == EAGAIN)
1433 			goto retry;
1434 		if (saverr != ENOENT)
1435 			return (1);
1436 	}
1437 	(void) close(pfd);
1438 
1439 	if (info.pr_pid != pid &&
1440 	    info.pr_uid == uid && info.pr_euid == euid)
1441 		return (0);
1442 	else
1443 		return (1);
1444 }
1445 
1446 
1447 /*
1448  * FUNCTION: check_user_process
1449  */
1450 /*ARGSUSED*/
1451 static void *
1452 check_user_process(void *arg)
1453 {
1454 
1455 	DIR		*dp;
1456 	struct dirent	*ep;
1457 	int		found;
1458 	char		*me = "check_user_process";
1459 
1460 	/*CONSTCOND*/
1461 	while (1) {
1462 		(void) sleep(60);
1463 
1464 		found = 0;
1465 
1466 		/*
1467 		 * search the /proc directory and look at each process
1468 		 */
1469 		if ((dp = opendir("/proc")) == NULL) {
1470 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1471 			(me, "unable to open the /proc directory\n");
1472 			continue;
1473 		}
1474 
1475 		/* for each active process */
1476 		while (ep = readdir(dp)) {
1477 			if (ep->d_name[0] == '.')    /* skip . and .. */
1478 				continue;
1479 			if (check_uid(ep->d_name) == 0) {
1480 				found = 1;
1481 				break;
1482 			}
1483 		}
1484 
1485 		/*
1486 		 * if no process running as the PUN uid found, exit
1487 		 * to kill this PUN
1488 		 */
1489 		if (found == 0) {
1490 			(void) closedir(dp);
1491 			exit(1);
1492 		}
1493 		(void) closedir(dp);
1494 	}
1495 	/* NOTREACHED */
1496 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1497 }
1498 
1499 static nscd_rc_t
1500 init_user_proc_monitor() {
1501 
1502 	int	errnum;
1503 	char	*me = "init_user_proc_monitor";
1504 
1505 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1506 	(me, "initializing the user process monitor\n");
1507 
1508 	/*
1509 	 * start a thread to make sure there is at least a process
1510 	 * running as the PUN user. If not, terminate this PUN.
1511 	 */
1512 	if (thr_create(NULL, NULL, check_user_process,
1513 		NULL, THR_DETACHED, NULL) != 0) {
1514 		errnum = errno;
1515 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1516 		(me, "thr_create: %s\n", strerror(errnum));
1517 		return (NSCD_THREAD_CREATE_ERROR);
1518 	}
1519 
1520 	return (NSCD_SUCCESS);
1521 }
1522 
1523 static void *
1524 get_smf_prop(const char *var, char type, void *def_val)
1525 {
1526 	scf_simple_prop_t	*prop;
1527 	void			*val;
1528 	char			*me = "get_smf_prop";
1529 
1530 	prop = scf_simple_prop_get(NULL, NULL, "config", var);
1531 	if (prop) {
1532 		switch (type) {
1533 		case 'b':
1534 			val = scf_simple_prop_next_boolean(prop);
1535 			if (val != NULL)
1536 				(void) memcpy(def_val, val, sizeof (uint8_t));
1537 			break;
1538 
1539 		case 'i':
1540 			val = scf_simple_prop_next_integer(prop);
1541 			if (val != NULL)
1542 				(void) memcpy(def_val, val, sizeof (int64_t));
1543 			break;
1544 		}
1545 		scf_simple_prop_free(prop);
1546 	}
1547 
1548 	if (prop == NULL || val == NULL) {
1549 		char	vs[64];
1550 
1551 		switch (type) {
1552 		case 'b':
1553 			if (*(uint8_t *)def_val)
1554 				(void) strcpy(vs, "yes");
1555 			else
1556 				(void) strcpy(vs, "no");
1557 
1558 			break;
1559 
1560 		case 'i':
1561 			(void) sprintf(vs, "%lld", *(int64_t *)def_val);
1562 			break;
1563 
1564 		}
1565 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT)
1566 		(me, "no value for config/%s (%s). "
1567 		    "Using default \"%s\"\n", var,
1568 		    scf_strerror(scf_error()), vs);
1569 	}
1570 
1571 	return (def_val);
1572 }
1573