xref: /illumos-gate/usr/src/cmd/nscd/nscd_selfcred.c (revision f67ca41a3fe371a8ac34045eb45b3c5449ee601c)
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 2006 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, killing all child processes\n",
435 		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",
789 			iam);
790 
791 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
792 			NSCD_SELF_CRED_MAIN_IMPOSTER);
793 	}
794 
795 	/* only forker handles fork requests */
796 	if (_whoami != NSCD_FORKER) {
797 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
798 		(me, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n");
799 
800 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
801 			NSCD_SELF_CRED_WRONG_NSCD);
802 	}
803 
804 	/* fork a child for the slot assigned by the main nscd */
805 	f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf);
806 	slot = f->slot;
807 	/* set the uid/gid as assigned by the main nscd */
808 	set2uid = f->uid;
809 	set2gid = f->gid;
810 
811 	/* ignore bad slot number */
812 	if (slot < 0 || slot >= max_pu_nscd) {
813 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
814 		(me, "bas slot number\n");
815 
816 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
817 		NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
818 	}
819 
820 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
821 	(me, "before fork1() ...\n");
822 
823 	if ((cid = fork1()) == 0) {
824 		_whoami = NSCD_CHILD;
825 
826 		/* close all except the log file */
827 		if (_logfd > 0) {
828 			int i;
829 			for (i = 0; i < _logfd; i++)
830 				(void) close(i);
831 			closefrom(_logfd + 1);
832 		} else
833 			closefrom(0);
834 
835 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
836 		(me, "child %d\n", getpid());
837 
838 		(void) setgid(set2gid);
839 		(void) setuid(set2uid);
840 
841 		/* set up the door and server thread pool */
842 		if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1)
843 			exit(-1);
844 
845 		/* tell libsldap to do self cred only */
846 		(void) setup_ldap_backend();
847 
848 		/* notify main that child is active */
849 		ih.slot = slot;
850 		for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
851 			ret = _nscd_doorcall_sendfd(_doorfd,
852 				NSCD_IMHERE | (NSCD_CHILD & NSCD_WHOAMI),
853 				&ih, sizeof (ih), NULL);
854 
855 			NSCD_RETURN_STATUS_SUCCESS(phdr);
856 	} if (cid  == (pid_t)-1) {
857 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
858 		(me, "forker unable to fork ...\n");
859 
860 		/* enter the maintenance mode */
861 		if ((fmri = getenv("SMF_FMRI")) != NULL) {
862 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
863 			(me, "entering maintenance mode ...\n");
864 			(void) smf_maintain_instance(fmri, SMF_TEMPORARY);
865 		}
866 		exit(0);
867 	} else {
868 		/*
869 		 * start the monitor so as to exit as early as
870 		 * possible if no other processes are running
871 		 * with the same PUN uid (i.e., this PUN is
872 		 * not needed any more)
873 		 */
874 		(void) init_user_proc_monitor();
875 
876 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
877 		(me, "child forked:  parent pid = %d, child pid = %d\n",
878 		getpid(), cid);
879 
880 		NSCD_SET_STATUS_SUCCESS(phdr);
881 	}
882 
883 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
884 	(me, "after fork\n");
885 }
886 
887 static void
888 selfcred_fork(
889 	void		*buf,
890 	int		doorfd,
891 	int		cslot,
892 	uid_t		uid,
893 	gid_t		gid)
894 {
895 	int		ret;
896 	nscd_fork_t	f;
897 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
898 	char		*me = "selfcred_fork";
899 
900 	/* if no door fd, do nothing */
901 	if (doorfd == -1) {
902 		NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
903 			NSCD_SELF_CRED_NO_DOOR);
904 	}
905 
906 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
907 	(me, "sending fork request to door %d for slot %d "
908 		"(uid = %d, gid = %d)\n", doorfd, cslot, uid, gid);
909 
910 	f.slot = cslot;
911 	f.uid = uid;
912 	f.gid = gid;
913 
914 	ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI),
915 		&f, sizeof (f), NULL, 0, phdr);
916 
917 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
918 	(me, "fork request sent to door %d for slot %d (rc = %d)\n",
919 		doorfd, cslot, ret);
920 
921 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
922 
923 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
924 		(me, "fork request sent to door %d for slot %d failed: "
925 		"status = %d, errno = %s, nscd status = %d\n", doorfd,
926 		cslot, NSCD_GET_STATUS(phdr), strerror(NSCD_GET_ERRNO(phdr)),
927 		NSCD_GET_NSCD_STATUS(phdr));
928 
929 	}
930 }
931 
932 void
933 _nscd_proc_alt_get(
934 	void		*buf,
935 	int		*door)
936 {
937 	int		errnum;
938 	uid_t		set2uid;
939 	gid_t		set2gid;
940 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
941 	char		*me = "_nscd_proc_alt_get";
942 	ucred_t		*uc = NULL;
943 	child_t		*ch;
944 
945 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
946 	(me, "getting an alternate door ...\n");
947 
948 	/* make sure there is a door to talk to the forker */
949 	if (forking_door == -1) {
950 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
951 		(me, "no door to talk to the forker\n");
952 
953 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
954 		NSCD_SELF_CRED_NO_FORKER);
955 	}
956 
957 	/* get door client's credential information */
958 	if (door_ucred(&uc) != 0) {
959 		errnum = errno;
960 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
961 		(me, "door_ucred failed: %s\n", strerror(errnum));
962 
963 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
964 			NSCD_DOOR_UCRED_ERROR);
965 	}
966 
967 	/* get door client's effective uid and effective gid */
968 	set2uid = ucred_geteuid(uc);
969 	set2gid = ucred_getegid(uc);
970 	ucred_free(uc);
971 	uc = NULL;
972 
973 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
974 	(me, "child uid = %d, gid = %d\n", set2uid, set2gid);
975 
976 	/* is a slot available ? if not, no one to serve */
977 	if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) {
978 
979 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
980 		(me, "no child slot available (child array = %p, slot = %d)\n",
981 			child, ch->child_slot);
982 
983 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
984 			NSCD_SELF_CRED_NO_CHILD_SLOT);
985 	}
986 
987 	/* create the per user nscd if necessary */
988 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
989 
990 		nss_pheader_t	phdr1;
991 		NSCD_CLEAR_STATUS(&phdr1);
992 
993 		(void) mutex_lock(ch->mutex);
994 		if (ch->child_state == CHILD_STATE_UIDKNOWN) {
995 
996 			/* ask forker to fork a new child */
997 			selfcred_fork(&phdr1, forking_door, ch->child_slot,
998 				set2uid, set2gid);
999 			if (NSCD_STATUS_IS_NOT_OK(&phdr1)) {
1000 				(void) mutex_unlock(ch->mutex);
1001 				NSCD_COPY_STATUS(phdr, &phdr1);
1002 				return;
1003 			}
1004 			ch->child_state = CHILD_STATE_FORKSENT;
1005 		}
1006 
1007 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1008 		(me, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1009 				ch->child_slot, set2uid, set2gid);
1010 
1011 		/* wait for the per user nscd to become available */
1012 		while (ch->child_state == CHILD_STATE_FORKSENT) {
1013 			timestruc_t to;
1014 			int err;
1015 			int ttl = 5;
1016 
1017 			to.tv_sec = ttl;
1018 			to.tv_nsec = 0;
1019 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1020 				(me, "cond_reltimedwait %d seconds\n", ttl);
1021 			err = cond_reltimedwait(ch->cond, ch->mutex, &to);
1022 			if (err == ETIME) {
1023 				ch->child_state =
1024 					CHILD_STATE_UIDKNOWN;
1025 				_NSCD_LOG(NSCD_LOG_SELF_CRED,
1026 					NSCD_LOG_LEVEL_DEBUG)
1027 				(me, "door wait timedout (slot = %d)\n",
1028 					ch->child_slot);
1029 				break;
1030 			}
1031 		}
1032 		(void) mutex_unlock(ch->mutex);
1033 	}
1034 
1035 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
1036 
1037 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1038 			NSCD_SELF_CRED_INVALID_SLOT_STATE);
1039 	}
1040 
1041 	*door = ch->child_door;
1042 
1043 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1044 	(me, "returning door %d for slot %d, uid %d, gid = %d\n",
1045 		*door, ch->child_slot, set2uid, set2gid);
1046 
1047 	NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0);
1048 }
1049 
1050 static char **
1051 cpargv(
1052 	int	argc,
1053 	char	**inargv)
1054 {
1055 	char	**newargv;
1056 	int	c = 4;
1057 	int	i = 0, j, k = 0, n = 0;
1058 
1059 	newargv = (char **)calloc(c + 1, sizeof (char *));
1060 	if (newargv == NULL)
1061 		return (NULL);
1062 
1063 	newargv[n] = strdup(inargv[0]);
1064 	if (newargv[n++] == NULL) {
1065 		free(newargv);
1066 		return (NULL);
1067 	}
1068 
1069 	newargv[n] = strdup("-F");
1070 	if (newargv[n++] == NULL) {
1071 		free(newargv[0]);
1072 		free(newargv);
1073 		return (NULL);
1074 	}
1075 
1076 	for (i = 1; i < argc; i++) {
1077 		if (strcmp(inargv[i], "-f") == 0)
1078 			k = 2;
1079 		if (k  == 0)
1080 			continue;
1081 
1082 		newargv[n] = strdup(inargv[i]);
1083 		if (newargv[n] == NULL) {
1084 			for (j = 0; j < n; j++)
1085 				free(newargv[j]);
1086 			free(newargv);
1087 			return (NULL);
1088 		}
1089 
1090 		k--;
1091 		n++;
1092 	}
1093 	return (newargv);
1094 }
1095 
1096 
1097 void
1098 _nscd_start_forker(
1099 	char	*path,
1100 	int	argc,
1101 	char	**argv)
1102 {
1103 	pid_t	cid;
1104 	struct	rlimit rl;
1105 	char	*me = "_nscd_start_forker";
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 			/* set NOFILE to unlimited */
1132 			rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1133 			if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1134 				_NSCD_LOG(NSCD_LOG_SELF_CRED,
1135 					NSCD_LOG_LEVEL_ERROR)
1136 				(me, "Cannot set open file limit: %s\n",
1137 					strerror(errno));
1138 				exit(1);
1139 			}
1140 
1141 			/* enable child nscd management */
1142 			(void) _nscd_init_cslots();
1143 			break;
1144 	}
1145 }
1146 
1147 static nscd_rc_t
1148 get_ldap_funcs(
1149 	char			*name,
1150 	void			**func_p)
1151 {
1152 	char			*me = "get_ldap_funcs";
1153 	static void		*handle = NULL;
1154 	void			*sym;
1155 
1156 	if (name == NULL && handle != NULL) {
1157 		(void) dlclose(handle);
1158 		return (NSCD_SUCCESS);
1159 	}
1160 	/* no handle to close, it's OK */
1161 	if (name == NULL)
1162 		return (NSCD_SUCCESS);
1163 
1164 	if (handle == NULL) {
1165 		handle = dlopen("libsldap.so.1", RTLD_LAZY);
1166 		if (handle == NULL) {
1167 
1168 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1169 			(me, "unable to dlopen libsldap.so.1");
1170 			return (NSCD_CFG_DLOPEN_ERROR);
1171 		}
1172 	}
1173 
1174 	if ((sym = dlsym(handle, name)) == NULL) {
1175 
1176 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1177 			(me, "unable to find symbol %s", name);
1178 			return (NSCD_CFG_DLSYM_ERROR);
1179 	} else
1180 		(void) memcpy(func_p, &sym, sizeof (void *));
1181 
1182 	return (NSCD_SUCCESS);
1183 }
1184 
1185 
1186 int
1187 _nscd_is_self_cred_on(int recheck, char **dblist)
1188 {
1189 	static int	checked = 0;
1190 	static int	is_on = 0;
1191 	static int	(*ldap_func)();
1192 	char		*srcs = "ldap"; /* only ldap support self cred */
1193 	int		ldap_on = 0;
1194 
1195 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_config";
1196 	ns_ldap_self_gssapi_config_t ldap_config;
1197 
1198 	if (checked && !recheck) {
1199 		if (is_on && dblist != NULL)
1200 			*dblist = selfcred_dbs;
1201 		return (is_on);
1202 	}
1203 
1204 	if (selfcred_dbs != NULL)
1205 		free(selfcred_dbs);
1206 	selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs);
1207 
1208 	/*
1209 	 * also check the ldap backend to see if
1210 	 * the configuration there is good for
1211 	 * doing self credentialing
1212 	 */
1213 	if (ldap_func == NULL)
1214 		(void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1215 	if (ldap_func != NULL) {
1216 		if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS &&
1217 			ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
1218 			ldap_on = 1;
1219 	}
1220 
1221 	is_on = pu_nscd_enabled == nscd_true &&
1222 			ldap_on && selfcred_dbs != NULL;
1223 
1224 	checked = 1;
1225 
1226 	if (is_on && dblist != NULL)
1227 		*dblist = selfcred_dbs;
1228 
1229 	return (is_on);
1230 }
1231 
1232 static nscd_rc_t
1233 setup_ldap_backend()
1234 {
1235 	nscd_rc_t	rc;
1236 	static void	(*ldap_func)();
1237 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_only_set";
1238 	if (ldap_func == NULL)
1239 		rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1240 	if (ldap_func != NULL) {
1241 		ldap_func(1);
1242 		return (NSCD_SUCCESS);
1243 	}
1244 	return (rc);
1245 }
1246 
1247 /*ARGSUSED*/
1248 void
1249 _nscd_peruser_getadmin(
1250 	void		*buf,
1251 	int		buf_size)
1252 {
1253 	void		*result_mn = NSCD_N2N_DOOR_DATA(void, buf);
1254 	int		errnum = 0;
1255 	int		ret;
1256 	uid_t		uid;
1257 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
1258 	char		*me = "_nscd_peruser_getadmin";
1259 	ucred_t		*uc = NULL;
1260 	child_t		*ch;
1261 
1262 	/* get door client's credential information */
1263 	if (door_ucred(&uc) != 0) {
1264 		errnum = errno;
1265 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1266 		(me, "door_ucred failed: %s\n", strerror(errnum));
1267 
1268 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
1269 			NSCD_DOOR_UCRED_ERROR);
1270 	}
1271 
1272 	/* get door client's effective uid */
1273 	uid = ucred_geteuid(uc);
1274 	ucred_free(uc);
1275 	uc = NULL;
1276 
1277 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1278 	(me, "per user get admin ... (uid = %d)\n", uid);
1279 
1280 	/* is the per-user nscd running ? if not, no one to serve */
1281 	ch = get_cslot(uid, 1);
1282 	if (ch == NULL) {
1283 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1284 			NSCD_SELF_CRED_NO_CHILD_SLOT);
1285 	}
1286 
1287 	ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN,
1288 		NULL, sizeof (nscd_admin_t), result_mn,
1289 		sizeof (nscd_admin_t), phdr);
1290 
1291 	if (ret == NSS_SUCCESS) {
1292 		phdr->data_len = sizeof (nscd_admin_t);
1293 		return;
1294 	}
1295 }
1296 
1297 static void
1298 set_selfcred_cfg(
1299 	char	param,
1300 	void	*data)
1301 {
1302 	int64_t	prop_int;
1303 	char	*me = "set_selfcred_cfg";
1304 
1305 	if (param == 'a' || param == 'e') {
1306 		pu_nscd_enabled = *(uint8_t *)get_smf_prop(
1307 			"enable_per_user_lookup", 'b', data);
1308 
1309 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1310 		(me, "self cred config: enabled = %d\n", pu_nscd_enabled);
1311 	}
1312 
1313 	if (param == 'a' || param == 't') {
1314 		prop_int = *(int *)data;
1315 		pu_nscd_ttl = *(int64_t *)get_smf_prop(
1316 			"per_user_nscd_time_to_live", 'i', &prop_int);
1317 
1318 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1319 		(me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl);
1320 	}
1321 }
1322 
1323 /* ARGSUSED */
1324 nscd_rc_t
1325 _nscd_cfg_selfcred_notify(
1326 	void				*data,
1327 	struct nscd_cfg_param_desc	*pdesc,
1328 	nscd_cfg_id_t			*nswdb,
1329 	nscd_cfg_flag_t			dflag,
1330 	nscd_cfg_error_t		**errorp,
1331 	void				*cookie)
1332 {
1333 
1334 	nscd_cfg_global_selfcred_t	*sc_cfg = &nscd_selfcred_cfg_g;
1335 	int				off;
1336 
1337 	/*
1338 	 * At init time, the whole group of config params are received.
1339 	 * At update time, group or individual parameter value could
1340 	 * be received.
1341 	 */
1342 
1343 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1344 
1345 		*sc_cfg = *(nscd_cfg_global_selfcred_t *)data;
1346 
1347 		off = offsetof(nscd_cfg_global_selfcred_t,
1348 			enable_selfcred);
1349 		set_selfcred_cfg('e', (char *)data + off);
1350 
1351 		off = offsetof(nscd_cfg_global_selfcred_t,
1352 			max_per_user_nscd);
1353 		set_selfcred_cfg('n', (char *)data + off);
1354 
1355 		off = offsetof(nscd_cfg_global_selfcred_t,
1356 			per_user_nscd_ttl);
1357 		set_selfcred_cfg('t', (char *)data + off);
1358 
1359 		return (NSCD_SUCCESS);
1360 	}
1361 
1362 	/*
1363 	 * individual config parameter
1364 	 */
1365 	off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred);
1366 	if (pdesc->p_offset == off) {
1367 		sc_cfg->enable_selfcred = *(nscd_bool_t *)data;
1368 		set_selfcred_cfg('e', data);
1369 		return (NSCD_SUCCESS);
1370 	}
1371 
1372 	off = offsetof(nscd_cfg_global_selfcred_t, max_per_user_nscd);
1373 	if (pdesc->p_offset == off) {
1374 		sc_cfg->max_per_user_nscd = *(int *)data;
1375 		set_selfcred_cfg('n', data);
1376 		return (NSCD_SUCCESS);
1377 	}
1378 
1379 	off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl);
1380 	if (pdesc->p_offset == off) {
1381 		sc_cfg->per_user_nscd_ttl = *(int *)data;
1382 		set_selfcred_cfg('t', data);
1383 		return (NSCD_SUCCESS);
1384 	}
1385 
1386 	return (NSCD_SUCCESS);
1387 }
1388 
1389 /* ARGSUSED */
1390 nscd_rc_t
1391 _nscd_cfg_selfcred_verify(
1392 	void				*data,
1393 	struct	nscd_cfg_param_desc	*pdesc,
1394 	nscd_cfg_id_t			*nswdb,
1395 	nscd_cfg_flag_t			dflag,
1396 	nscd_cfg_error_t		**errorp,
1397 	void				**cookie)
1398 {
1399 
1400 	return (NSCD_SUCCESS);
1401 }
1402 
1403 /* ARGSUSED */
1404 nscd_rc_t
1405 _nscd_cfg_selfcred_get_stat(
1406 	void				**stat,
1407 	struct nscd_cfg_stat_desc	*sdesc,
1408 	nscd_cfg_id_t			*nswdb,
1409 	nscd_cfg_flag_t			*dflag,
1410 	void				(**free_stat)(void *stat),
1411 	nscd_cfg_error_t		**errorp)
1412 {
1413 	return (NSCD_SUCCESS);
1414 }
1415 
1416 static int
1417 check_uid(char *pid_name)
1418 {
1419 	char		pname[PATH_MAX];
1420 	static pid_t	pid = 0;
1421 	static uid_t	uid = 0;
1422 	static uid_t	euid = 0;
1423 	int		pfd; /* file descriptor for /proc/<pid>/psinfo */
1424 	psinfo_t 	info;  /* process information from /proc */
1425 
1426 	if (uid == 0)  {
1427 		pid = getpid();
1428 		uid = getuid();
1429 		euid = geteuid();
1430 	}
1431 
1432 	(void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name);
1433 retry:
1434 	if ((pfd = open(pname, O_RDONLY)) == -1) {
1435 		/* Process may have exited */
1436 			return (1);
1437 	}
1438 
1439 	/*
1440 	 * Get the info structure for the process and close quickly.
1441 	 */
1442 	if (read(pfd, (char *)&info, sizeof (info)) < 0) {
1443 		int	saverr = errno;
1444 
1445 		(void) close(pfd);
1446 		if (saverr == EAGAIN)
1447 			goto retry;
1448 		if (saverr != ENOENT)
1449 			return (1);
1450 	}
1451 	(void) close(pfd);
1452 
1453 	if (info.pr_pid != pid &&
1454 		info.pr_uid == uid && info.pr_euid == euid)
1455 		return (0);
1456 	else
1457 		return (1);
1458 }
1459 
1460 
1461 /*
1462  * FUNCTION: check_user_process
1463  */
1464 /*ARGSUSED*/
1465 static void *
1466 check_user_process(void *arg)
1467 {
1468 
1469 	DIR		*dp;
1470 	struct dirent	*ep;
1471 	int		found;
1472 	char		*me = "check_user_process";
1473 
1474 	/*CONSTCOND*/
1475 	while (1) {
1476 		(void) sleep(60);
1477 
1478 		found = 0;
1479 
1480 		/*
1481 		 * search the /proc directory and look at each process
1482 		 */
1483 		if ((dp = opendir("/proc")) == NULL) {
1484 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1485 			(me, "unable to open the /proc directory\n");
1486 			continue;
1487 		}
1488 
1489 		/* for each active process */
1490 		while (ep = readdir(dp)) {
1491 			if (ep->d_name[0] == '.')    /* skip . and .. */
1492 				continue;
1493 			if (check_uid(ep->d_name) == 0) {
1494 				found = 1;
1495 				break;
1496 			}
1497 		}
1498 
1499 		/*
1500 		 * if no process running as the PUN uid found, exit
1501 		 * to kill this PUN
1502 		 */
1503 		if (found == 0) {
1504 			(void) closedir(dp);
1505 			exit(1);
1506 		}
1507 		(void) closedir(dp);
1508 	}
1509 	/* NOTREACHED */
1510 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1511 }
1512 
1513 static nscd_rc_t
1514 init_user_proc_monitor() {
1515 
1516 	int	errnum;
1517 	char	*me = "init_user_proc_monitor";
1518 
1519 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1520 	(me, "initializing the user process monitor\n");
1521 
1522 	/*
1523 	 * start a thread to make sure there is at least a process
1524 	 * running as the PUN user. If not, terminate this PUN.
1525 	 */
1526 	if (thr_create(NULL, NULL, check_user_process,
1527 		NULL, THR_DETACHED, NULL) != 0) {
1528 		errnum = errno;
1529 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1530 		(me, "thr_create: %s\n", strerror(errnum));
1531 		return (NSCD_THREAD_CREATE_ERROR);
1532 	}
1533 
1534 	return (NSCD_SUCCESS);
1535 }
1536 
1537 static void *
1538 get_smf_prop(const char *var, char type, void *def_val)
1539 {
1540 	scf_simple_prop_t	*prop;
1541 	void			*val = def_val;
1542 	char			*me = "get_smf_prop";
1543 
1544 	prop = scf_simple_prop_get(NULL, NULL, "config", var);
1545 	if (prop) {
1546 		switch (type) {
1547 		case 'b':
1548 			val = scf_simple_prop_next_boolean(prop);
1549 			break;
1550 
1551 		case 'i':
1552 			val = scf_simple_prop_next_integer(prop);
1553 			break;
1554 
1555 		case 'c':
1556 			val = scf_simple_prop_next_count(prop);
1557 			break;
1558 		}
1559 		scf_simple_prop_free(prop);
1560 	}
1561 
1562 	if (prop == NULL || val == NULL) {
1563 		char	vs[64];
1564 
1565 		switch (type) {
1566 		case 'b':
1567 			if (*(uint8_t *)def_val)
1568 				(void) strcpy(vs, "yes");
1569 			else
1570 				(void) strcpy(vs, "no");
1571 
1572 			break;
1573 
1574 		case 'i':
1575 		case 'c':
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 (val);
1587 }
1588