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