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