xref: /illumos-gate/usr/src/cmd/nscd/nscd_selfcred.c (revision 98c080d502548e68bb9815459ea56e6ae282c430)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
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 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
411 	(me, "door (%d) monitor exited (rc = %d)\n", fd, ret);
412 
413 	return (ret);
414 }
415 
416 /*ARGSUSED*/
417 static void *
418 forker_monitor(
419 	void		*arg)
420 {
421 	pid_t		fpid;
422 	char		*fmri;
423 	char		*me = "forker_monitor";
424 
425 	/* wait until forker exits */
426 	fpid = forker_pid;
427 	(void) selfcred_pulse(forking_door);
428 
429 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
430 	(me, "forker (pid = %d) exited or crashed, "
431 	    "killing all child processes\n", fpid);
432 
433 	(void) mutex_lock(&forking_lock);
434 	forking_door = -1;
435 	forker_pid = -1;
436 	(void) mutex_unlock(&forking_lock);
437 
438 	/* forker exited/crashed, kill all the child processes */
439 	_nscd_kill_all_children();
440 
441 	/* restart forker */
442 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
443 	(me, "restarting the forker ...\n");
444 
445 	switch (fpid = fork1()) {
446 	case (pid_t)-1:
447 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
448 		(me, "unable to fork and start the forker ...\n");
449 
450 		/* enter the maintenance mode */
451 		if ((fmri = getenv("SMF_FMRI")) != NULL) {
452 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
453 			(me, "entering maintenance mode ...\n");
454 			(void) smf_maintain_instance(fmri, SMF_TEMPORARY);
455 		}
456 		return ((void *)1);
457 		break;
458 	case 0:
459 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
460 		(me, "execv path = %s\n", execpath);
461 
462 		(void) execv(execpath, execargv);
463 		exit(0);
464 		break;
465 	default:
466 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
467 		(me, "new forker's pid is %d\n", fpid);
468 		forker_pid = fpid;
469 		break;
470 	}
471 
472 	return (NULL);
473 }
474 
475 static void *
476 child_monitor(
477 	void		*arg)
478 {
479 	child_t		*ch = (child_t *)arg;
480 	pid_t		cpid;
481 	char		*me = "child_monitor";
482 
483 	/* wait until child exits */
484 	cpid = ch->child_pid;
485 	(void) selfcred_pulse(ch->child_door);
486 
487 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
488 		(me, "child (pid = %d) exited or crashed ...\n", cpid);
489 
490 	/* return the slot used by the child */
491 	return_cslot(ch);
492 
493 	return (NULL);
494 }
495 
496 
497 void
498 _nscd_proc_iamhere(
499 	void		*buf,
500 	door_desc_t	*dp,
501 	uint_t		n_desc,
502 	int		iam)
503 {
504 	int		cslot;
505 	child_t		*ch;
506 	int		errnum;
507 	ucred_t		*uc = NULL;
508 	uid_t		uid;
509 	nscd_imhere_t	*ih;
510 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
511 	char		*me = "_nscd_proc_iamhere";
512 
513 
514 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
515 	(me, "%d receives iamhere from %d\n", _whoami, iam);
516 
517 	if (door_ucred(&uc) != 0) {
518 		errnum = errno;
519 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
520 		(me, "door_ucred failed: %s\n", strerror(errnum));
521 
522 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
523 		    NSCD_DOOR_UCRED_ERROR);
524 	}
525 	uid = ucred_geteuid(uc);
526 
527 	switch (iam) {
528 
529 	case NSCD_MAIN:
530 		if (_whoami == NSCD_MAIN || uid != main_uid) {
531 			/*
532 			 * I'm main, or uid from door is not correct,
533 			 * this must be an imposter
534 			 */
535 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
536 			(me, "MAIN IMPOSTER CAUGHT!\n");
537 
538 
539 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
540 			    NSCD_SELF_CRED_MAIN_IMPOSTER);
541 		}
542 		break;
543 
544 	case NSCD_FORKER:
545 		if (_whoami == NSCD_FORKER || uid != forker_uid) {
546 			/*
547 			 * I'm forker, or uid from door is not correct,
548 			 * this must be an imposter
549 			 */
550 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
551 			(me, "FORKER IMPOSTER CAUGHT!\n");
552 
553 
554 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
555 			    NSCD_SELF_CRED_FORKER_IMPOSTER);
556 			break;
557 		}
558 
559 		/* only main needs to know the forker */
560 		if (_whoami != NSCD_MAIN) {
561 
562 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
563 			    NSCD_SELF_CRED_WRONG_NSCD);
564 			break;
565 		}
566 
567 		if (ucred_getpid(uc) != forker_pid) {
568 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
569 			(me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
570 			    ucred_getpid(uc), forker_pid);
571 
572 
573 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
574 			    NSCD_SELF_CRED_FORKER_IMPOSTER);
575 			break;
576 		}
577 
578 		if (n_desc < 1) {
579 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
580 			(me, "BAD FORKER, NO DOOR!\n");
581 
582 
583 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
584 			    NSCD_SELF_CRED_NO_DOOR);
585 			break;
586 		}
587 
588 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
589 		    dp->d_data.d_desc.d_descriptor > 0 &&
590 		    dp->d_data.d_desc.d_id != 0) {
591 			(void) mutex_lock(&forking_lock);
592 			if (forking_door != -1)
593 				(void) close(forking_door);
594 			forking_door = dp->d_data.d_desc.d_descriptor;
595 			(void) mutex_unlock(&forking_lock);
596 
597 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
598 			(me, "forking door is %d\n", forking_door);
599 
600 			NSCD_SET_STATUS_SUCCESS(phdr);
601 		} else {
602 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
603 			break;
604 		}
605 
606 		/* monitor the forker nscd */
607 		(void) thr_create(NULL, 0, forker_monitor, NULL,
608 		    THR_DETACHED, NULL);
609 
610 		break;
611 
612 	case NSCD_CHILD:
613 		if (_whoami != NSCD_MAIN) {
614 			/* child nscd can only talk to the main nscd */
615 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
616 			(me, "CHILD IMPOSTER CAUGHT!\n");
617 
618 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
619 			    NSCD_SELF_CRED_CHILD_IMPOSTER);
620 			break;
621 		}
622 
623 		/* get the main nscd assigned slot number */
624 		ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf);
625 		cslot = ih->slot;
626 		(void) mutex_lock(&child_lock);
627 		if (cslot < 0 || cslot >= max_pu_nscd)
628 			ch = NULL;
629 		else
630 			ch = child[cslot];
631 		(void) mutex_unlock(&child_lock);
632 
633 		if (ch == NULL) {
634 			/* Bad slot number */
635 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
636 			(me, "bad slot number %d\n", cslot);
637 
638 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
639 			    NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
640 			break;
641 		}
642 
643 		if (uid != ch->child_uid) {
644 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
645 		(me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
646 		    uid, ch->child_uid);
647 
648 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
649 			    NSCD_SELF_CRED_CHILD_IMPOSTER);
650 			break;
651 		}
652 
653 		if (ch->child_state != CHILD_STATE_UIDKNOWN &&
654 		    ch->child_state != CHILD_STATE_FORKSENT) {
655 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
656 			(me, "invalid slot/child state (%d) for uid %d\n",
657 			    ch->child_state, uid);
658 
659 			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
660 			    NSCD_SELF_CRED_INVALID_SLOT_STATE);
661 			break;
662 		}
663 
664 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
665 		(me, "d_descriptor = %d, d_id = %lld\n",
666 		    dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id);
667 
668 		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
669 		    dp->d_data.d_desc.d_descriptor > 0 &&
670 		    dp->d_data.d_desc.d_id != 0) {
671 			(void) mutex_lock(ch->mutex);
672 			if (ch->child_door != -1)
673 				(void) close(ch->child_door);
674 			ch->child_door = dp->d_data.d_desc.d_descriptor;
675 			ch->child_pid  = ucred_getpid(uc);
676 			ch->child_state  = CHILD_STATE_PIDKNOWN;
677 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
678 			(me, "child in slot %d has door %d\n",
679 			    cslot, ch->child_door);
680 
681 			/*
682 			 * let waiters know that the child is ready to
683 			 * serve
684 			 */
685 			(void) cond_broadcast(ch->cond);
686 			(void) mutex_unlock(ch->mutex);
687 
688 			/* monitor the child nscd */
689 			(void) thr_create(NULL, 0, child_monitor,
690 			    ch, THR_DETACHED, NULL);
691 			NSCD_SET_STATUS_SUCCESS(phdr);
692 			break;
693 		} else {
694 			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
695 		}
696 		break;
697 	}
698 
699 	ucred_free(uc);
700 	uc = NULL;
701 }
702 
703 void
704 _nscd_proc_pulse(
705 	void		*buf,
706 	int		iam)
707 {
708 	long		last_active;
709 	int		done = 0;
710 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
711 	char		*me = "_nscd_proc_pulse";
712 
713 	/* only main nscd sends pulse */
714 	if (iam != NSCD_MAIN) {
715 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
716 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam);
717 
718 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
719 		    NSCD_SELF_CRED_MAIN_IMPOSTER);
720 	}
721 
722 	/* forker doesn't return stats, it just pauses */
723 	if (_whoami == NSCD_FORKER) {
724 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
725 		(me, "forker ready to pause ...\n");
726 
727 		/*CONSTCOND*/
728 		while (1)
729 			(void) pause();
730 
731 		NSCD_RETURN_STATUS_SUCCESS(phdr);
732 	}
733 
734 	/* remember the current activity sequence number */
735 	(void) mutex_lock(&activity_lock);
736 	last_active = activity;
737 	(void) mutex_unlock(&activity_lock);
738 
739 	while (!done) {
740 
741 		/* allow per_user_nscd_ttl seconds of inactivity */
742 		(void) sleep(pu_nscd_ttl);
743 
744 		(void) mutex_lock(&activity_lock);
745 		if (last_active == activity)
746 			done = 1;
747 		else {
748 			last_active = activity;
749 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
750 			(me, "active, sleep again for %d seconds\n",
751 			    pu_nscd_ttl);
752 		}
753 		(void) mutex_unlock(&activity_lock);
754 	}
755 
756 	/* no activity in the specified seconds, exit and disconnect */
757 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
758 	(me, "no activity in the last %d seconds, exit\n", pu_nscd_ttl);
759 	exit(0);
760 }
761 
762 void
763 _nscd_proc_fork(
764 	void		*buf,
765 	int		iam)
766 {
767 	int		slot;
768 	int		ret;
769 	char		*fmri;
770 	pid_t		cid;
771 	uid_t		set2uid;
772 	gid_t		set2gid;
773 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
774 	char		*me = "_nscd_proc_fork";
775 	nscd_fork_t	*f;
776 	nscd_imhere_t	ih;
777 
778 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
779 	(me, "%d receives fork request from %d\n", _whoami, iam);
780 
781 	/* only main nscd sends fork requests */
782 	if (iam != NSCD_MAIN) {
783 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
784 		(me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam);
785 
786 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
787 		    NSCD_SELF_CRED_MAIN_IMPOSTER);
788 	}
789 
790 	/* only forker handles fork requests */
791 	if (_whoami != NSCD_FORKER) {
792 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
793 		(me, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n");
794 
795 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
796 		    NSCD_SELF_CRED_WRONG_NSCD);
797 	}
798 
799 	/* fork a child for the slot assigned by the main nscd */
800 	f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf);
801 	slot = f->slot;
802 	/* set the uid/gid as assigned by the main nscd */
803 	set2uid = f->uid;
804 	set2gid = f->gid;
805 
806 	/* ignore bad slot number */
807 	if (slot < 0 || slot >= max_pu_nscd) {
808 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
809 		(me, "bas slot number\n");
810 
811 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
812 		    NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
813 	}
814 
815 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
816 	(me, "before fork1() ...\n");
817 
818 	if ((cid = fork1()) == 0) {
819 		_whoami = NSCD_CHILD;
820 
821 		/*
822 		 * remember when this child nscd starts
823 		 * (replace the forker start time)
824 		 */
825 		_nscd_set_start_time(1);
826 
827 		/* close all except the log file */
828 		if (_logfd > 0) {
829 			int i;
830 			for (i = 0; i < _logfd; i++)
831 				(void) close(i);
832 			closefrom(_logfd + 1);
833 		} else
834 			closefrom(0);
835 
836 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
837 		(me, "child %d\n", getpid());
838 
839 		(void) setgid(set2gid);
840 		(void) setuid(set2uid);
841 
842 		/* set up the door and server thread pool */
843 		if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1)
844 			exit(-1);
845 
846 		/* tell libsldap to do self cred only */
847 		(void) setup_ldap_backend();
848 
849 		/* notify main that child is active */
850 		ih.slot = slot;
851 		for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
852 			ret = _nscd_doorcall_sendfd(_doorfd,
853 			    NSCD_IMHERE | (NSCD_CHILD & NSCD_WHOAMI),
854 			    &ih, sizeof (ih), NULL);
855 
856 			NSCD_RETURN_STATUS_SUCCESS(phdr);
857 	} if (cid  == (pid_t)-1) {
858 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
859 		(me, "forker unable to fork ...\n");
860 
861 		/* enter the maintenance mode */
862 		if ((fmri = getenv("SMF_FMRI")) != NULL) {
863 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
864 			(me, "entering maintenance mode ...\n");
865 			(void) smf_maintain_instance(fmri, SMF_TEMPORARY);
866 		}
867 		exit(0);
868 	} else {
869 		/*
870 		 * start the monitor so as to exit as early as
871 		 * possible if no other processes are running
872 		 * with the same PUN uid (i.e., this PUN is
873 		 * not needed any more)
874 		 */
875 		(void) init_user_proc_monitor();
876 
877 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
878 		(me, "child forked:  parent pid = %d, child pid = %d\n",
879 		    getpid(), cid);
880 
881 		NSCD_SET_STATUS_SUCCESS(phdr);
882 	}
883 
884 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
885 	(me, "after fork\n");
886 }
887 
888 static void
889 selfcred_fork(
890 	void		*buf,
891 	int		doorfd,
892 	int		cslot,
893 	uid_t		uid,
894 	gid_t		gid)
895 {
896 	int		ret;
897 	nscd_fork_t	f;
898 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
899 	char		*me = "selfcred_fork";
900 
901 	/* if no door fd, do nothing */
902 	if (doorfd == -1) {
903 		NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
904 		    NSCD_SELF_CRED_NO_DOOR);
905 	}
906 
907 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
908 	(me, "sending fork request to door %d for slot %d "
909 	    "(uid = %d, gid = %d)\n", doorfd, cslot, uid, gid);
910 
911 	f.slot = cslot;
912 	f.uid = uid;
913 	f.gid = gid;
914 
915 	ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI),
916 	    &f, sizeof (f), NULL, 0, phdr);
917 
918 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
919 	(me, "fork request sent to door %d for slot %d (rc = %d)\n",
920 	    doorfd, cslot, ret);
921 
922 	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
923 
924 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
925 		(me, "fork request sent to door %d for slot %d failed: "
926 		    "status = %d, errno = %s, nscd status = %d\n", doorfd,
927 		    cslot, NSCD_GET_STATUS(phdr),
928 		    strerror(NSCD_GET_ERRNO(phdr)),
929 		    NSCD_GET_NSCD_STATUS(phdr));
930 
931 	}
932 }
933 
934 void
935 _nscd_proc_alt_get(
936 	void		*buf,
937 	int		*door)
938 {
939 	int		errnum;
940 	uid_t		set2uid;
941 	gid_t		set2gid;
942 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
943 	char		*me = "_nscd_proc_alt_get";
944 	ucred_t		*uc = NULL;
945 	child_t		*ch;
946 
947 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
948 	(me, "getting an alternate door ...\n");
949 
950 	/* make sure there is a door to talk to the forker */
951 	if (forking_door == -1) {
952 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
953 		(me, "no door to talk to the forker\n");
954 
955 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
956 		    NSCD_SELF_CRED_NO_FORKER);
957 	}
958 
959 	/* get door client's credential information */
960 	if (door_ucred(&uc) != 0) {
961 		errnum = errno;
962 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
963 		(me, "door_ucred failed: %s\n", strerror(errnum));
964 
965 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
966 		    NSCD_DOOR_UCRED_ERROR);
967 	}
968 
969 	/* get door client's effective uid and effective gid */
970 	set2uid = ucred_geteuid(uc);
971 	set2gid = ucred_getegid(uc);
972 	ucred_free(uc);
973 	uc = NULL;
974 
975 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
976 	(me, "child uid = %d, gid = %d\n", set2uid, set2gid);
977 
978 	/* is a slot available ? if not, no one to serve */
979 	if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) {
980 
981 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
982 		(me, "no child slot available (child array = %p, slot = %d)\n",
983 		    child, ch->child_slot);
984 
985 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
986 		    NSCD_SELF_CRED_NO_CHILD_SLOT);
987 	}
988 
989 	/* create the per user nscd if necessary */
990 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
991 
992 		nss_pheader_t	phdr1;
993 		NSCD_CLEAR_STATUS(&phdr1);
994 
995 		(void) mutex_lock(ch->mutex);
996 		if (ch->child_state == CHILD_STATE_UIDKNOWN) {
997 
998 			/* ask forker to fork a new child */
999 			selfcred_fork(&phdr1, forking_door, ch->child_slot,
1000 			    set2uid, set2gid);
1001 			if (NSCD_STATUS_IS_NOT_OK(&phdr1)) {
1002 				(void) mutex_unlock(ch->mutex);
1003 				NSCD_COPY_STATUS(phdr, &phdr1);
1004 				return;
1005 			}
1006 			ch->child_state = CHILD_STATE_FORKSENT;
1007 		}
1008 
1009 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1010 		(me, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1011 		    ch->child_slot, set2uid, set2gid);
1012 
1013 		/* wait for the per user nscd to become available */
1014 		while (ch->child_state == CHILD_STATE_FORKSENT) {
1015 			timestruc_t to;
1016 			int err;
1017 			int ttl = 5;
1018 
1019 			to.tv_sec = ttl;
1020 			to.tv_nsec = 0;
1021 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1022 				(me, "cond_reltimedwait %d seconds\n", ttl);
1023 			err = cond_reltimedwait(ch->cond, ch->mutex, &to);
1024 			if (err == ETIME) {
1025 				ch->child_state = CHILD_STATE_UIDKNOWN;
1026 				_NSCD_LOG(NSCD_LOG_SELF_CRED,
1027 				    NSCD_LOG_LEVEL_DEBUG)
1028 				(me, "door wait timedout (slot = %d)\n",
1029 				    ch->child_slot);
1030 				break;
1031 			}
1032 		}
1033 		(void) mutex_unlock(ch->mutex);
1034 	}
1035 
1036 	if (ch->child_state != CHILD_STATE_PIDKNOWN) {
1037 
1038 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1039 		    NSCD_SELF_CRED_INVALID_SLOT_STATE);
1040 	}
1041 
1042 	*door = ch->child_door;
1043 
1044 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1045 	(me, "returning door %d for slot %d, uid %d, gid = %d\n",
1046 	    *door, ch->child_slot, set2uid, set2gid);
1047 
1048 	NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0);
1049 }
1050 
1051 static char **
1052 cpargv(
1053 	int	argc,
1054 	char	**inargv)
1055 {
1056 	char	**newargv;
1057 	int	c = 4;
1058 	int	i = 0, j, k = 0, n = 0;
1059 
1060 	newargv = (char **)calloc(c + 1, sizeof (char *));
1061 	if (newargv == NULL)
1062 		return (NULL);
1063 
1064 	newargv[n] = strdup(inargv[0]);
1065 	if (newargv[n++] == NULL) {
1066 		free(newargv);
1067 		return (NULL);
1068 	}
1069 
1070 	newargv[n] = strdup("-F");
1071 	if (newargv[n++] == NULL) {
1072 		free(newargv[0]);
1073 		free(newargv);
1074 		return (NULL);
1075 	}
1076 
1077 	for (i = 1; i < argc; i++) {
1078 		if (strcmp(inargv[i], "-f") == 0)
1079 			k = 2;
1080 		if (k  == 0)
1081 			continue;
1082 
1083 		newargv[n] = strdup(inargv[i]);
1084 		if (newargv[n] == NULL) {
1085 			for (j = 0; j < n; j++)
1086 				free(newargv[j]);
1087 			free(newargv);
1088 			return (NULL);
1089 		}
1090 
1091 		k--;
1092 		n++;
1093 	}
1094 	return (newargv);
1095 }
1096 
1097 
1098 void
1099 _nscd_start_forker(
1100 	char	*path,
1101 	int	argc,
1102 	char	**argv)
1103 {
1104 	pid_t	cid;
1105 
1106 	/* if self cred is not configured, do nothing */
1107 	if (!_nscd_is_self_cred_on(1, NULL))
1108 		return;
1109 
1110 	/* save pathname and generate the new argv for the forker */
1111 	execpath = strdup(path);
1112 	execargv = cpargv(argc, argv);
1113 	if (execpath == NULL || execargv == NULL)
1114 		exit(1);
1115 
1116 	switch (cid = fork1()) {
1117 		case (pid_t)-1:
1118 			exit(1);
1119 			break;
1120 		case 0:
1121 			/* start the forker nscd */
1122 			(void) execv(path, execargv);
1123 			exit(0);
1124 			break;
1125 		default:
1126 			/* main nscd */
1127 			/* remember process id of the forker */
1128 			forker_pid = cid;
1129 
1130 			/* enable child nscd management */
1131 			(void) _nscd_init_cslots();
1132 			break;
1133 	}
1134 }
1135 
1136 static nscd_rc_t
1137 get_ldap_funcs(
1138 	char			*name,
1139 	void			**func_p)
1140 {
1141 	char			*me = "get_ldap_funcs";
1142 	static void		*handle = NULL;
1143 	void			*sym;
1144 
1145 	if (name == NULL && handle != NULL) {
1146 		(void) dlclose(handle);
1147 		return (NSCD_SUCCESS);
1148 	}
1149 	/* no handle to close, it's OK */
1150 	if (name == NULL)
1151 		return (NSCD_SUCCESS);
1152 
1153 	if (handle == NULL) {
1154 		handle = dlopen("libsldap.so.1", RTLD_LAZY);
1155 		if (handle == NULL) {
1156 
1157 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1158 			(me, "unable to dlopen libsldap.so.1");
1159 			return (NSCD_CFG_DLOPEN_ERROR);
1160 		}
1161 	}
1162 
1163 	if ((sym = dlsym(handle, name)) == NULL) {
1164 
1165 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1166 			(me, "unable to find symbol %s", name);
1167 			return (NSCD_CFG_DLSYM_ERROR);
1168 	} else
1169 		(void) memcpy(func_p, &sym, sizeof (void *));
1170 
1171 	return (NSCD_SUCCESS);
1172 }
1173 
1174 
1175 int
1176 _nscd_is_self_cred_on(int recheck, char **dblist)
1177 {
1178 	static int	checked = 0;
1179 	static int	is_on = 0;
1180 	static int	(*ldap_func)();
1181 	char		*srcs = "ldap"; /* only ldap support self cred */
1182 	int		ldap_on = 0;
1183 
1184 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_config";
1185 	ns_ldap_self_gssapi_config_t ldap_config;
1186 
1187 	if (checked && !recheck) {
1188 		if (is_on && dblist != NULL)
1189 			*dblist = selfcred_dbs;
1190 		return (is_on);
1191 	}
1192 
1193 	if (selfcred_dbs != NULL)
1194 		free(selfcred_dbs);
1195 	selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs);
1196 
1197 	if (selfcred_dbs == NULL) {
1198 		is_on =  0;
1199 		checked = 1;
1200 		return (0);
1201 	}
1202 
1203 	/*
1204 	 * also check the ldap backend to see if
1205 	 * the configuration there is good for
1206 	 * doing self credentialing
1207 	 */
1208 	if (ldap_func == NULL)
1209 		(void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1210 	if (ldap_func != NULL) {
1211 		if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS &&
1212 		    ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
1213 			ldap_on = 1;
1214 	}
1215 
1216 	is_on = (pu_nscd_enabled == nscd_true) && ldap_on;
1217 
1218 	checked = 1;
1219 
1220 	if (is_on && dblist != NULL)
1221 		*dblist = selfcred_dbs;
1222 
1223 	return (is_on);
1224 }
1225 
1226 static nscd_rc_t
1227 setup_ldap_backend()
1228 {
1229 	nscd_rc_t	rc;
1230 	static void	(*ldap_func)();
1231 	char		*ldap_sc_func = "__ns_ldap_self_gssapi_only_set";
1232 	if (ldap_func == NULL)
1233 		rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1234 	if (ldap_func != NULL) {
1235 		ldap_func(1);
1236 		return (NSCD_SUCCESS);
1237 	}
1238 	return (rc);
1239 }
1240 
1241 /*ARGSUSED*/
1242 void
1243 _nscd_peruser_getadmin(
1244 	void		*buf,
1245 	int		buf_size)
1246 {
1247 	void		*result_mn = NSCD_N2N_DOOR_DATA(void, buf);
1248 	int		errnum = 0;
1249 	int		ret;
1250 	uid_t		uid;
1251 	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
1252 	char		*me = "_nscd_peruser_getadmin";
1253 	ucred_t		*uc = NULL;
1254 	child_t		*ch;
1255 
1256 	/* get door client's credential information */
1257 	if (door_ucred(&uc) != 0) {
1258 		errnum = errno;
1259 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1260 		(me, "door_ucred failed: %s\n", strerror(errnum));
1261 
1262 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
1263 		    NSCD_DOOR_UCRED_ERROR);
1264 	}
1265 
1266 	/* get door client's effective uid */
1267 	uid = ucred_geteuid(uc);
1268 	ucred_free(uc);
1269 	uc = NULL;
1270 
1271 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1272 	(me, "per user get admin ... (uid = %d)\n", uid);
1273 
1274 	/* is the per-user nscd running ? if not, no one to serve */
1275 	ch = get_cslot(uid, 1);
1276 	if (ch == NULL) {
1277 		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1278 		    NSCD_SELF_CRED_NO_CHILD_SLOT);
1279 	}
1280 
1281 	ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN,
1282 	    NULL, sizeof (nscd_admin_t), result_mn,
1283 	    sizeof (nscd_admin_t), phdr);
1284 
1285 	if (ret == NSS_SUCCESS) {
1286 		phdr->data_len = sizeof (nscd_admin_t);
1287 		return;
1288 	}
1289 }
1290 
1291 static void
1292 set_selfcred_cfg(
1293 	char	param,
1294 	void	*data)
1295 {
1296 	int64_t	prop_int;
1297 	uint8_t prop_boolean;
1298 	char	*me = "set_selfcred_cfg";
1299 
1300 	if (param == 'e') {
1301 		prop_boolean = *(uint8_t *)data;
1302 		pu_nscd_enabled = *(uint8_t *)get_smf_prop(
1303 		    "enable_per_user_lookup", 'b', &prop_boolean);
1304 
1305 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1306 		(me, "self cred config: enabled = %d\n", pu_nscd_enabled);
1307 	}
1308 
1309 	if (param == 't') {
1310 		prop_int = *(int *)data;
1311 		pu_nscd_ttl = *(int64_t *)get_smf_prop(
1312 		    "per_user_nscd_time_to_live", 'i', &prop_int);
1313 
1314 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1315 		(me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl);
1316 	}
1317 }
1318 
1319 /* ARGSUSED */
1320 nscd_rc_t
1321 _nscd_cfg_selfcred_notify(
1322 	void				*data,
1323 	struct nscd_cfg_param_desc	*pdesc,
1324 	nscd_cfg_id_t			*nswdb,
1325 	nscd_cfg_flag_t			dflag,
1326 	nscd_cfg_error_t		**errorp,
1327 	void				*cookie)
1328 {
1329 
1330 	nscd_cfg_global_selfcred_t	*sc_cfg = &nscd_selfcred_cfg_g;
1331 	int				off;
1332 
1333 	/*
1334 	 * At init time, the whole group of config params are received.
1335 	 * At update time, group or individual parameter value could
1336 	 * be received.
1337 	 */
1338 
1339 	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1340 
1341 		*sc_cfg = *(nscd_cfg_global_selfcred_t *)data;
1342 
1343 		off = offsetof(nscd_cfg_global_selfcred_t,
1344 		    enable_selfcred);
1345 		set_selfcred_cfg('e', (char *)data + off);
1346 
1347 		off = offsetof(nscd_cfg_global_selfcred_t,
1348 		    per_user_nscd_ttl);
1349 		set_selfcred_cfg('t', (char *)data + off);
1350 
1351 		return (NSCD_SUCCESS);
1352 	}
1353 
1354 	/*
1355 	 * individual config parameter
1356 	 */
1357 	off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred);
1358 	if (pdesc->p_offset == off) {
1359 		sc_cfg->enable_selfcred = *(nscd_bool_t *)data;
1360 		set_selfcred_cfg('e', data);
1361 		return (NSCD_SUCCESS);
1362 	}
1363 
1364 	off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl);
1365 	if (pdesc->p_offset == off) {
1366 		sc_cfg->per_user_nscd_ttl = *(int *)data;
1367 		set_selfcred_cfg('t', data);
1368 		return (NSCD_SUCCESS);
1369 	}
1370 
1371 	return (NSCD_SUCCESS);
1372 }
1373 
1374 /* ARGSUSED */
1375 nscd_rc_t
1376 _nscd_cfg_selfcred_verify(
1377 	void				*data,
1378 	struct	nscd_cfg_param_desc	*pdesc,
1379 	nscd_cfg_id_t			*nswdb,
1380 	nscd_cfg_flag_t			dflag,
1381 	nscd_cfg_error_t		**errorp,
1382 	void				**cookie)
1383 {
1384 
1385 	return (NSCD_SUCCESS);
1386 }
1387 
1388 /* ARGSUSED */
1389 nscd_rc_t
1390 _nscd_cfg_selfcred_get_stat(
1391 	void				**stat,
1392 	struct nscd_cfg_stat_desc	*sdesc,
1393 	nscd_cfg_id_t			*nswdb,
1394 	nscd_cfg_flag_t			*dflag,
1395 	void				(**free_stat)(void *stat),
1396 	nscd_cfg_error_t		**errorp)
1397 {
1398 	return (NSCD_SUCCESS);
1399 }
1400 
1401 static int
1402 check_uid(char *pid_name)
1403 {
1404 	char		pname[PATH_MAX];
1405 	static pid_t	pid = 0;
1406 	static uid_t	uid = 0;
1407 	static uid_t	euid = 0;
1408 	int		pfd; /* file descriptor for /proc/<pid>/psinfo */
1409 	psinfo_t 	info;  /* process information from /proc */
1410 
1411 	if (uid == 0)  {
1412 		pid = getpid();
1413 		uid = getuid();
1414 		euid = geteuid();
1415 	}
1416 
1417 	(void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name);
1418 retry:
1419 	if ((pfd = open(pname, O_RDONLY)) == -1) {
1420 		/* Process may have exited */
1421 			return (1);
1422 	}
1423 
1424 	/*
1425 	 * Get the info structure for the process and close quickly.
1426 	 */
1427 	if (read(pfd, (char *)&info, sizeof (info)) < 0) {
1428 		int	saverr = errno;
1429 
1430 		(void) close(pfd);
1431 		if (saverr == EAGAIN)
1432 			goto retry;
1433 		if (saverr != ENOENT)
1434 			return (1);
1435 	}
1436 	(void) close(pfd);
1437 
1438 	if (info.pr_pid != pid &&
1439 	    info.pr_uid == uid && info.pr_euid == euid)
1440 		return (0);
1441 	else
1442 		return (1);
1443 }
1444 
1445 
1446 /*
1447  * FUNCTION: check_user_process
1448  */
1449 /*ARGSUSED*/
1450 static void *
1451 check_user_process(void *arg)
1452 {
1453 
1454 	DIR		*dp;
1455 	struct dirent	*ep;
1456 	int		found;
1457 	char		*me = "check_user_process";
1458 
1459 	/*CONSTCOND*/
1460 	while (1) {
1461 		(void) sleep(60);
1462 
1463 		found = 0;
1464 
1465 		/*
1466 		 * search the /proc directory and look at each process
1467 		 */
1468 		if ((dp = opendir("/proc")) == NULL) {
1469 			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1470 			(me, "unable to open the /proc directory\n");
1471 			continue;
1472 		}
1473 
1474 		/* for each active process */
1475 		while (ep = readdir(dp)) {
1476 			if (ep->d_name[0] == '.')    /* skip . and .. */
1477 				continue;
1478 			if (check_uid(ep->d_name) == 0) {
1479 				found = 1;
1480 				break;
1481 			}
1482 		}
1483 
1484 		/*
1485 		 * if no process running as the PUN uid found, exit
1486 		 * to kill this PUN
1487 		 */
1488 		if (found == 0) {
1489 			(void) closedir(dp);
1490 			exit(1);
1491 		}
1492 		(void) closedir(dp);
1493 	}
1494 	/* NOTREACHED */
1495 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1496 }
1497 
1498 static nscd_rc_t
1499 init_user_proc_monitor() {
1500 
1501 	int	errnum;
1502 	char	*me = "init_user_proc_monitor";
1503 
1504 	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1505 	(me, "initializing the user process monitor\n");
1506 
1507 	/*
1508 	 * start a thread to make sure there is at least a process
1509 	 * running as the PUN user. If not, terminate this PUN.
1510 	 */
1511 	if (thr_create(NULL, NULL, check_user_process,
1512 		NULL, THR_DETACHED, NULL) != 0) {
1513 		errnum = errno;
1514 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1515 		(me, "thr_create: %s\n", strerror(errnum));
1516 		return (NSCD_THREAD_CREATE_ERROR);
1517 	}
1518 
1519 	return (NSCD_SUCCESS);
1520 }
1521 
1522 static void *
1523 get_smf_prop(const char *var, char type, void *def_val)
1524 {
1525 	scf_simple_prop_t	*prop;
1526 	void			*val;
1527 	char			*me = "get_smf_prop";
1528 
1529 	prop = scf_simple_prop_get(NULL, NULL, "config", var);
1530 	if (prop) {
1531 		switch (type) {
1532 		case 'b':
1533 			val = scf_simple_prop_next_boolean(prop);
1534 			if (val != NULL)
1535 				(void) memcpy(def_val, val, sizeof (uint8_t));
1536 			break;
1537 
1538 		case 'i':
1539 			val = scf_simple_prop_next_integer(prop);
1540 			if (val != NULL)
1541 				(void) memcpy(def_val, val, sizeof (int64_t));
1542 			break;
1543 		}
1544 		scf_simple_prop_free(prop);
1545 	}
1546 
1547 	if (prop == NULL || val == NULL) {
1548 		char	vs[64];
1549 
1550 		switch (type) {
1551 		case 'b':
1552 			if (*(uint8_t *)def_val)
1553 				(void) strcpy(vs, "yes");
1554 			else
1555 				(void) strcpy(vs, "no");
1556 
1557 			break;
1558 
1559 		case 'i':
1560 			(void) sprintf(vs, "%lld", *(int64_t *)def_val);
1561 			break;
1562 
1563 		}
1564 		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT)
1565 		(me, "no value for config/%s (%s). "
1566 		    "Using default \"%s\"\n", var,
1567 		    scf_strerror(scf_error()), vs);
1568 	}
1569 
1570 	return (def_val);
1571 }
1572