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