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