xref: /illumos-gate/usr/src/uts/common/os/session.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn35248  * Common Development and Distribution License (the "License").
69acbbeafSnn35248  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/file.h>
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/signal.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/policy.h>
397c478bd9Sstevel@tonic-gate #include <sys/conf.h>
407c478bd9Sstevel@tonic-gate #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate #include <sys/proc.h>
427c478bd9Sstevel@tonic-gate #include <sys/session.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
469acbbeafSnn35248 #include <sys/fs/snode.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate sess_t session0 = {
499acbbeafSnn35248 	&pid0,		/* s_sidp */
509acbbeafSnn35248 	{0},		/* s_lock */
517c478bd9Sstevel@tonic-gate 	1,		/* s_ref */
529acbbeafSnn35248 	B_FALSE,	/* s_sighuped */
539acbbeafSnn35248 	B_FALSE,	/* s_exit */
549acbbeafSnn35248 	0,		/* s_exit_cv */
559acbbeafSnn35248 	0,		/* s_cnt */
569acbbeafSnn35248 	0,		/* s_cnt_cv */
577c478bd9Sstevel@tonic-gate 	NODEV,		/* s_dev */
587c478bd9Sstevel@tonic-gate 	NULL,		/* s_vp */
597c478bd9Sstevel@tonic-gate 	NULL		/* s_cred */
607c478bd9Sstevel@tonic-gate };
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate void
sess_hold(proc_t * p)639acbbeafSnn35248 sess_hold(proc_t *p)
647c478bd9Sstevel@tonic-gate {
659acbbeafSnn35248 	ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
669acbbeafSnn35248 	mutex_enter(&p->p_sessp->s_lock);
679acbbeafSnn35248 	p->p_sessp->s_ref++;
689acbbeafSnn35248 	mutex_exit(&p->p_sessp->s_lock);
699acbbeafSnn35248 }
709acbbeafSnn35248 
719acbbeafSnn35248 void
sess_rele(sess_t * sp,boolean_t pidlock_held)729acbbeafSnn35248 sess_rele(sess_t *sp, boolean_t pidlock_held)
739acbbeafSnn35248 {
749acbbeafSnn35248 	ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
759acbbeafSnn35248 
769acbbeafSnn35248 	mutex_enter(&sp->s_lock);
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	ASSERT(sp->s_ref != 0);
799acbbeafSnn35248 	if (--sp->s_ref > 0) {
809acbbeafSnn35248 		mutex_exit(&sp->s_lock);
819acbbeafSnn35248 		return;
829acbbeafSnn35248 	}
839acbbeafSnn35248 	ASSERT(sp->s_ref == 0);
849acbbeafSnn35248 
859acbbeafSnn35248 	/*
869acbbeafSnn35248 	 * It's ok to free this session structure now because we know
879acbbeafSnn35248 	 * that no one else can have a pointer to it.  We know this
889acbbeafSnn35248 	 * to be true because the only time that s_ref can possibly
899acbbeafSnn35248 	 * be incremented is when pidlock or p_splock is held AND there
909acbbeafSnn35248 	 * is a proc_t that points to that session structure.  In that
919acbbeafSnn35248 	 * case we are guaranteed that the s_ref is at least 1 since there
929acbbeafSnn35248 	 * is a proc_t that points to it.  So when s_ref finally drops to
939acbbeafSnn35248 	 * zero then no one else has a reference (and hence pointer) to
949acbbeafSnn35248 	 * this session structure and there is no valid proc_t pointing
959acbbeafSnn35248 	 * to this session structure anymore so, no one can acquire a
969acbbeafSnn35248 	 * reference (and pointer) to this session structure so it's
979acbbeafSnn35248 	 * ok to free it here.
989acbbeafSnn35248 	 */
999acbbeafSnn35248 
1007c478bd9Sstevel@tonic-gate 	if (sp == &session0)
1017c478bd9Sstevel@tonic-gate 		panic("sp == &session0");
1029acbbeafSnn35248 
1039acbbeafSnn35248 	/* make sure there are no outstanding holds */
1049acbbeafSnn35248 	ASSERT(sp->s_cnt == 0);
1059acbbeafSnn35248 
1069acbbeafSnn35248 	/* make sure there is no exit in progress */
1079acbbeafSnn35248 	ASSERT(!sp->s_exit);
1089acbbeafSnn35248 
1099acbbeafSnn35248 	/* make sure someone already freed any ctty */
1109acbbeafSnn35248 	ASSERT(sp->s_vp == NULL);
1119acbbeafSnn35248 	ASSERT(sp->s_dev == NODEV);
1129acbbeafSnn35248 
1139acbbeafSnn35248 	if (!pidlock_held)
1149acbbeafSnn35248 		mutex_enter(&pidlock);
1157c478bd9Sstevel@tonic-gate 	PID_RELE(sp->s_sidp);
1169acbbeafSnn35248 	if (!pidlock_held)
1179acbbeafSnn35248 		mutex_exit(&pidlock);
1189acbbeafSnn35248 
1197c478bd9Sstevel@tonic-gate 	mutex_destroy(&sp->s_lock);
1209acbbeafSnn35248 	cv_destroy(&sp->s_cnt_cv);
1217c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (sess_t));
1227c478bd9Sstevel@tonic-gate }
1239acbbeafSnn35248 
1249acbbeafSnn35248 sess_t *
tty_hold(void)1259acbbeafSnn35248 tty_hold(void)
1269acbbeafSnn35248 {
1279acbbeafSnn35248 	proc_t		*p = curproc;
1289acbbeafSnn35248 	sess_t		*sp;
1299acbbeafSnn35248 	boolean_t	got_sig = B_FALSE;
1309acbbeafSnn35248 
1319acbbeafSnn35248 	/* make sure the caller isn't holding locks they shouldn't */
1329acbbeafSnn35248 	ASSERT(MUTEX_NOT_HELD(&pidlock));
1339acbbeafSnn35248 
1349acbbeafSnn35248 	for (;;) {
1359acbbeafSnn35248 		mutex_enter(&p->p_splock);	/* protect p->p_sessp */
1369acbbeafSnn35248 		sp = p->p_sessp;
1379acbbeafSnn35248 		mutex_enter(&sp->s_lock);	/* protect sp->* */
1389acbbeafSnn35248 
1399acbbeafSnn35248 		/* make sure the caller isn't holding locks they shouldn't */
1409acbbeafSnn35248 		ASSERT((sp->s_vp == NULL) ||
1419acbbeafSnn35248 		    MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
1429acbbeafSnn35248 
1439acbbeafSnn35248 		/*
1449acbbeafSnn35248 		 * If the session leader process is not exiting (and hence
1459acbbeafSnn35248 		 * not trying to release the session's ctty) then we can
1469acbbeafSnn35248 		 * safely grab a hold on the current session structure
1479acbbeafSnn35248 		 * and return it.  If on the other hand the session leader
1489acbbeafSnn35248 		 * process is exiting and clearing the ctty then we'll
1499acbbeafSnn35248 		 * wait till it's done before we loop around and grab a
1509acbbeafSnn35248 		 * hold on the session structure.
1519acbbeafSnn35248 		 */
1529acbbeafSnn35248 		if (!sp->s_exit)
1539acbbeafSnn35248 			break;
1549acbbeafSnn35248 
1559acbbeafSnn35248 		/* need to hold the session so it can't be freed */
1569acbbeafSnn35248 		sp->s_ref++;
1579acbbeafSnn35248 		mutex_exit(&p->p_splock);
1589acbbeafSnn35248 
1599acbbeafSnn35248 		/* Wait till the session leader is done */
1609acbbeafSnn35248 		if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
1619acbbeafSnn35248 			got_sig = B_TRUE;
1629acbbeafSnn35248 
1639acbbeafSnn35248 		/*
1649acbbeafSnn35248 		 * Now we need to drop our hold on the session structure,
1659acbbeafSnn35248 		 * but we can't hold any locks when we do this because
166*da6c28aaSamw 		 * sess_rele() may need to acquire pidlock.
1679acbbeafSnn35248 		 */
1689acbbeafSnn35248 		mutex_exit(&sp->s_lock);
1699acbbeafSnn35248 		sess_rele(sp, B_FALSE);
1709acbbeafSnn35248 
1719acbbeafSnn35248 		if (got_sig)
1729acbbeafSnn35248 			return (NULL);
1739acbbeafSnn35248 	}
1749acbbeafSnn35248 
1759acbbeafSnn35248 	/* whew, we finally got a hold */
1769acbbeafSnn35248 	sp->s_cnt++;
1779acbbeafSnn35248 	sp->s_ref++;
1789acbbeafSnn35248 	mutex_exit(&sp->s_lock);
1799acbbeafSnn35248 	mutex_exit(&p->p_splock);
1809acbbeafSnn35248 	return (sp);
1819acbbeafSnn35248 }
1829acbbeafSnn35248 
1839acbbeafSnn35248 void
tty_rele(sess_t * sp)1849acbbeafSnn35248 tty_rele(sess_t *sp)
1859acbbeafSnn35248 {
1869acbbeafSnn35248 	/* make sure the caller isn't holding locks they shouldn't */
1879acbbeafSnn35248 	ASSERT(MUTEX_NOT_HELD(&pidlock));
1889acbbeafSnn35248 
1899acbbeafSnn35248 	mutex_enter(&sp->s_lock);
1909acbbeafSnn35248 	if ((--sp->s_cnt) == 0)
1919acbbeafSnn35248 		cv_broadcast(&sp->s_cnt_cv);
1929acbbeafSnn35248 	mutex_exit(&sp->s_lock);
1939acbbeafSnn35248 
1949acbbeafSnn35248 	sess_rele(sp, B_FALSE);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate void
sess_create(void)1987c478bd9Sstevel@tonic-gate sess_create(void)
1997c478bd9Sstevel@tonic-gate {
2009acbbeafSnn35248 	proc_t *p = curproc;
2019acbbeafSnn35248 	sess_t *sp, *old_sp;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
2069acbbeafSnn35248 	cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/*
2099acbbeafSnn35248 	 * we need to grap p_lock to protect p_pgidp because
2109acbbeafSnn35248 	 * /proc looks at p_pgidp while holding only p_lock.
2119acbbeafSnn35248 	 *
2129acbbeafSnn35248 	 * we don't need to hold p->p_sessp->s_lock or get a hold on the
2139acbbeafSnn35248 	 * session structure since we're not actually updating any of
2149acbbeafSnn35248 	 * the contents of the old session structure.
2157c478bd9Sstevel@tonic-gate 	 */
2169acbbeafSnn35248 	mutex_enter(&pidlock);
2179acbbeafSnn35248 	mutex_enter(&p->p_lock);
2189acbbeafSnn35248 	mutex_enter(&p->p_splock);
2197c478bd9Sstevel@tonic-gate 
2209acbbeafSnn35248 	pgexit(p);
2219acbbeafSnn35248 
2229acbbeafSnn35248 	sp->s_sidp = p->p_pidp;
2237c478bd9Sstevel@tonic-gate 	sp->s_ref = 1;
2247c478bd9Sstevel@tonic-gate 	sp->s_dev = NODEV;
2257c478bd9Sstevel@tonic-gate 
2269acbbeafSnn35248 	old_sp = p->p_sessp;
2279acbbeafSnn35248 	p->p_sessp = sp;
2287c478bd9Sstevel@tonic-gate 
2299acbbeafSnn35248 	pgjoin(p, p->p_pidp);
2309acbbeafSnn35248 	PID_HOLD(p->p_pidp);
2317c478bd9Sstevel@tonic-gate 
2329acbbeafSnn35248 	mutex_exit(&p->p_splock);
2339acbbeafSnn35248 	mutex_exit(&p->p_lock);
2347c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
2359acbbeafSnn35248 
2369acbbeafSnn35248 	sess_rele(old_sp, B_FALSE);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2399acbbeafSnn35248 /*
2409acbbeafSnn35248  * Note that sess_ctty_clear() resets all the fields in the session
2419acbbeafSnn35248  * structure but doesn't release any holds or free any objects
2429acbbeafSnn35248  * that the session structure might currently point to.  it is the
2439acbbeafSnn35248  * callers responsibility to do this.
2449acbbeafSnn35248  */
2459acbbeafSnn35248 static void
sess_ctty_clear(sess_t * sp,stdata_t * stp)2469acbbeafSnn35248 sess_ctty_clear(sess_t *sp, stdata_t *stp)
2477c478bd9Sstevel@tonic-gate {
2489acbbeafSnn35248 	/*
2499acbbeafSnn35248 	 * Assert that we hold all the necessary locks.  We also need
2509acbbeafSnn35248 	 * to be holding proc_t->p_splock for the process associated
2519acbbeafSnn35248 	 * with this session, but since we don't have a proc pointer
2529acbbeafSnn35248 	 * passed in we can't assert this here.
2539acbbeafSnn35248 	 */
2549acbbeafSnn35248 	ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2559acbbeafSnn35248 	    MUTEX_HELD(&sp->s_lock));
2567c478bd9Sstevel@tonic-gate 
2579acbbeafSnn35248 	/* reset the session structure members to defaults */
2589acbbeafSnn35248 	sp->s_sighuped = B_FALSE;
2599acbbeafSnn35248 	sp->s_dev = NODEV;
2607c478bd9Sstevel@tonic-gate 	sp->s_vp = NULL;
261ad1660d0Smeem 	sp->s_cred = NULL;
2627c478bd9Sstevel@tonic-gate 
2639acbbeafSnn35248 	/* reset the stream session and group pointers */
2649acbbeafSnn35248 	stp->sd_pgidp = NULL;
2659acbbeafSnn35248 	stp->sd_sidp = NULL;
2669acbbeafSnn35248 }
2677c478bd9Sstevel@tonic-gate 
2689acbbeafSnn35248 static void
sess_ctty_set(proc_t * p,sess_t * sp,stdata_t * stp)2699acbbeafSnn35248 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
2709acbbeafSnn35248 {
2719acbbeafSnn35248 	cred_t	*crp;
2729acbbeafSnn35248 
2739acbbeafSnn35248 	/* Assert that we hold all the necessary locks. */
2749acbbeafSnn35248 	ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2759acbbeafSnn35248 	    MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
2769acbbeafSnn35248 
2779acbbeafSnn35248 	/* get holds on structures */
2789acbbeafSnn35248 	mutex_enter(&p->p_crlock);
2799acbbeafSnn35248 	crhold(crp = p->p_cred);
2809acbbeafSnn35248 	mutex_exit(&p->p_crlock);
2819acbbeafSnn35248 	PID_HOLD(sp->s_sidp);	/* requires pidlock */
2829acbbeafSnn35248 	PID_HOLD(sp->s_sidp);	/* requires pidlock */
2839acbbeafSnn35248 
2849acbbeafSnn35248 	/* update the session structure members */
2859acbbeafSnn35248 	sp->s_vp = makectty(stp->sd_vnode);
2869acbbeafSnn35248 	sp->s_dev = sp->s_vp->v_rdev;
2879acbbeafSnn35248 	sp->s_cred = crp;
2889acbbeafSnn35248 
2899acbbeafSnn35248 	/* update the stream emebers */
2909acbbeafSnn35248 	stp->sd_flag |= STRISTTY;	/* just to be sure */
2919acbbeafSnn35248 	stp->sd_sidp = sp->s_sidp;
2929acbbeafSnn35248 	stp->sd_pgidp = sp->s_sidp;
2939acbbeafSnn35248 }
2949acbbeafSnn35248 
2959acbbeafSnn35248 int
strctty(stdata_t * stp)2969acbbeafSnn35248 strctty(stdata_t *stp)
2979acbbeafSnn35248 {
2989acbbeafSnn35248 	sess_t		*sp;
2999acbbeafSnn35248 	proc_t		*p = curproc;
3009acbbeafSnn35248 	boolean_t	got_sig = B_FALSE;
3019acbbeafSnn35248 
3029acbbeafSnn35248 	/*
3039acbbeafSnn35248 	 * We are going to try to make stp the default ctty for the session
3049acbbeafSnn35248 	 * associated with curproc.  Not only does this require holding a
3059acbbeafSnn35248 	 * bunch of locks but it also requires waiting for any outstanding
306*da6c28aaSamw 	 * holds on the session structure (acquired via tty_hold()) to be
3079acbbeafSnn35248 	 * released.  Hence, we have the following for(;;) loop that will
308*da6c28aaSamw 	 * acquire our locks, do some sanity checks, and wait for the hold
3099acbbeafSnn35248 	 * count on the session structure to hit zero.  If we get a signal
3109acbbeafSnn35248 	 * while waiting for outstanding holds to be released then we abort
3119acbbeafSnn35248 	 * the operation and return.
3129acbbeafSnn35248 	 */
3139acbbeafSnn35248 	for (;;) {
3149acbbeafSnn35248 		mutex_enter(&stp->sd_lock);	/* protects sd_pgidp/sd_sidp */
3159acbbeafSnn35248 		mutex_enter(&pidlock);		/* protects p_pidp */
3169acbbeafSnn35248 		mutex_enter(&p->p_splock);	/* protects p_sessp */
3179acbbeafSnn35248 		sp = p->p_sessp;
3189acbbeafSnn35248 		mutex_enter(&sp->s_lock);	/* protects sp->* */
3199acbbeafSnn35248 
3209acbbeafSnn35248 		if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
3219acbbeafSnn35248 		    (stp->sd_sidp != NULL) ||		/* stp already ctty? */
3229acbbeafSnn35248 		    (p->p_pidp != sp->s_sidp) ||	/* we're not leader? */
3239acbbeafSnn35248 		    (sp->s_vp != NULL)) {		/* session has ctty? */
3247c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->s_lock);
3259acbbeafSnn35248 			mutex_exit(&p->p_splock);
3269acbbeafSnn35248 			mutex_exit(&pidlock);
3279acbbeafSnn35248 			mutex_exit(&stp->sd_lock);
3289acbbeafSnn35248 			return (ENOTTY);
3299acbbeafSnn35248 		}
3309acbbeafSnn35248 
3319acbbeafSnn35248 		/* sanity check.  we can't be exiting right now */
3329acbbeafSnn35248 		ASSERT(!sp->s_exit);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		/*
3359acbbeafSnn35248 		 * If no one else has a hold on this session structure
3369acbbeafSnn35248 		 * then we now have exclusive access to it, so break out
3379acbbeafSnn35248 		 * of this loop and update the session structure.
3387c478bd9Sstevel@tonic-gate 		 */
3399acbbeafSnn35248 		if (sp->s_cnt == 0)
3409acbbeafSnn35248 			break;
3417c478bd9Sstevel@tonic-gate 
3429acbbeafSnn35248 		/* need to hold the session so it can't be freed */
3439acbbeafSnn35248 		sp->s_ref++;
3449acbbeafSnn35248 
3459acbbeafSnn35248 		/* ain't locking order fun? */
3469acbbeafSnn35248 		mutex_exit(&p->p_splock);
3479acbbeafSnn35248 		mutex_exit(&pidlock);
3489acbbeafSnn35248 		mutex_exit(&stp->sd_lock);
3499acbbeafSnn35248 
3509acbbeafSnn35248 		if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
3519acbbeafSnn35248 			got_sig = B_TRUE;
3529acbbeafSnn35248 		mutex_exit(&sp->s_lock);
3539acbbeafSnn35248 		sess_rele(sp, B_FALSE);
3549acbbeafSnn35248 
3559acbbeafSnn35248 		if (got_sig)
3569acbbeafSnn35248 			return (EINTR);
3579acbbeafSnn35248 	}
3589acbbeafSnn35248 
3599acbbeafSnn35248 	/* set the session ctty bindings */
3609acbbeafSnn35248 	sess_ctty_set(p, sp, stp);
3619acbbeafSnn35248 
3629acbbeafSnn35248 	mutex_exit(&sp->s_lock);
3639acbbeafSnn35248 	mutex_exit(&p->p_splock);
3649acbbeafSnn35248 	mutex_exit(&pidlock);
3659acbbeafSnn35248 	mutex_exit(&stp->sd_lock);
3669acbbeafSnn35248 	return (0);
3679acbbeafSnn35248 }
3689acbbeafSnn35248 
3699acbbeafSnn35248 /*
370*da6c28aaSamw  * freectty_lock() attempts to acquire the army of locks required to free
3719acbbeafSnn35248  * the ctty associated with a given session leader process.  If it returns
3729acbbeafSnn35248  * successfully the following locks will be held:
3739acbbeafSnn35248  *	sd_lock, pidlock, p_splock, s_lock
3749acbbeafSnn35248  *
375*da6c28aaSamw  * as a secondary bit of convenience, freectty_lock() will also return
3769acbbeafSnn35248  * pointers to the session, ctty, and ctty stream associated with the
3779acbbeafSnn35248  * specified session leader process.
3789acbbeafSnn35248  */
3799acbbeafSnn35248 static boolean_t
freectty_lock(proc_t * p,sess_t ** spp,vnode_t ** vpp,stdata_t ** stpp,boolean_t at_exit)3809acbbeafSnn35248 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
3819acbbeafSnn35248     boolean_t at_exit)
3829acbbeafSnn35248 {
3839acbbeafSnn35248 	sess_t		*sp;
3849acbbeafSnn35248 	vnode_t		*vp;
3859acbbeafSnn35248 	stdata_t	*stp;
3869acbbeafSnn35248 
3879acbbeafSnn35248 	mutex_enter(&pidlock);			/* protect p_pidp */
3889acbbeafSnn35248 	mutex_enter(&p->p_splock);		/* protect p->p_sessp */
3899acbbeafSnn35248 	sp = p->p_sessp;
3909acbbeafSnn35248 	mutex_enter(&sp->s_lock);		/* protect sp->* */
3919acbbeafSnn35248 
3929acbbeafSnn35248 	if ((sp->s_sidp != p->p_pidp) ||	/* we're not leader? */
3939acbbeafSnn35248 	    (sp->s_vp == NULL)) {		/* no ctty? */
3949acbbeafSnn35248 		mutex_exit(&sp->s_lock);
3959acbbeafSnn35248 		mutex_exit(&p->p_splock);
3969acbbeafSnn35248 		mutex_exit(&pidlock);
3979acbbeafSnn35248 		return (B_FALSE);
3989acbbeafSnn35248 	}
3999acbbeafSnn35248 
4009acbbeafSnn35248 	vp = sp->s_vp;
4019acbbeafSnn35248 	stp = sp->s_vp->v_stream;
4029acbbeafSnn35248 
4039acbbeafSnn35248 	if (at_exit) {
4049acbbeafSnn35248 		/* stop anyone else calling tty_hold() */
4059acbbeafSnn35248 		sp->s_exit = B_TRUE;
4069acbbeafSnn35248 	} else {
4079acbbeafSnn35248 		/*
4089acbbeafSnn35248 		 * due to locking order we have to grab stp->sd_lock before
4099acbbeafSnn35248 		 * grabbing all the other proc/session locks.  but after we
4109acbbeafSnn35248 		 * drop all our current locks it's possible that someone
4119acbbeafSnn35248 		 * could come in and change our current session or close
4129acbbeafSnn35248 		 * the current ctty (vp) there by making sp or stp invalid.
4139acbbeafSnn35248 		 * (a VN_HOLD on vp won't protect stp because that only
4149acbbeafSnn35248 		 * prevents the vnode from being freed not closed.)  so
4159acbbeafSnn35248 		 * to prevent this we bump s_ref and s_cnt here.
4169acbbeafSnn35248 		 *
4179acbbeafSnn35248 		 * course this doesn't matter if we're the last thread in
4189acbbeafSnn35248 		 * an exiting process that is the session leader, since no
4199acbbeafSnn35248 		 * one else can change our session or free our ctty.
4209acbbeafSnn35248 		 */
4219acbbeafSnn35248 		sp->s_ref++;	/* hold the session structure */
4229acbbeafSnn35248 		sp->s_cnt++;	/* protect vp and stp */
4239acbbeafSnn35248 	}
4249acbbeafSnn35248 
4259acbbeafSnn35248 	/* drop our session locks */
4269acbbeafSnn35248 	mutex_exit(&sp->s_lock);
4279acbbeafSnn35248 	mutex_exit(&p->p_splock);
4289acbbeafSnn35248 	mutex_exit(&pidlock);
4299acbbeafSnn35248 
4309acbbeafSnn35248 	/* grab locks in the right order */
4319acbbeafSnn35248 	mutex_enter(&stp->sd_lock);		/* protects sd_pgidp/sd_sidp */
4329acbbeafSnn35248 	mutex_enter(&pidlock);			/* protect p_pidp */
4339acbbeafSnn35248 	mutex_enter(&p->p_splock);		/* protects p->p_sessp */
4349acbbeafSnn35248 	mutex_enter(&sp->s_lock);		/* protects sp->* */
4359acbbeafSnn35248 
4369acbbeafSnn35248 	/* if the session has changed, abort mission */
4379acbbeafSnn35248 	if (sp != p->p_sessp) {
4389acbbeafSnn35248 		/*
4399acbbeafSnn35248 		 * this can't happen during process exit since we're the
4409acbbeafSnn35248 		 * only thread in the process and we sure didn't change
4419acbbeafSnn35248 		 * our own session at this point.
4429acbbeafSnn35248 		 */
4439acbbeafSnn35248 		ASSERT(!at_exit);
4449acbbeafSnn35248 
4459acbbeafSnn35248 		/* release our locks and holds */
4469acbbeafSnn35248 		mutex_exit(&sp->s_lock);
4479acbbeafSnn35248 		mutex_exit(&p->p_splock);
4489acbbeafSnn35248 		mutex_exit(&pidlock);
4499acbbeafSnn35248 		mutex_exit(&stp->sd_lock);
4509acbbeafSnn35248 		tty_rele(sp);
4519acbbeafSnn35248 		return (B_FALSE);
4529acbbeafSnn35248 	}
4539acbbeafSnn35248 
4549acbbeafSnn35248 	/*
4559acbbeafSnn35248 	 * sanity checks.  none of this should have changed since we had
4569acbbeafSnn35248 	 * holds on the current ctty.
4579acbbeafSnn35248 	 */
4589acbbeafSnn35248 	ASSERT(sp->s_sidp == p->p_pidp);	/* we're the leader */
4599acbbeafSnn35248 	ASSERT(sp->s_vp != NULL);		/* a ctty exists */
4609acbbeafSnn35248 	ASSERT(vp == sp->s_vp);
4619acbbeafSnn35248 	ASSERT(stp == sp->s_vp->v_stream);
4629acbbeafSnn35248 
4639acbbeafSnn35248 	/* release our holds */
4649acbbeafSnn35248 	if (!at_exit) {
4659acbbeafSnn35248 		if ((--(sp)->s_cnt) == 0)
4669acbbeafSnn35248 			cv_broadcast(&sp->s_cnt_cv);
4679acbbeafSnn35248 		sp->s_ref--;
4689acbbeafSnn35248 		ASSERT(sp->s_ref > 0);
4699acbbeafSnn35248 	}
4709acbbeafSnn35248 
4719acbbeafSnn35248 	/* return our pointers */
4729acbbeafSnn35248 	*spp = sp;
4739acbbeafSnn35248 	*vpp = vp;
4749acbbeafSnn35248 	*stpp = stp;
4759acbbeafSnn35248 
4769acbbeafSnn35248 	return (B_TRUE);
4779acbbeafSnn35248 }
4789acbbeafSnn35248 
4799acbbeafSnn35248 /*
4809acbbeafSnn35248  * Returns B_FALSE if no signal is sent to the process group associated with
4819acbbeafSnn35248  * this ctty.  Returns B_TRUE if a signal is sent to the process group.
4829acbbeafSnn35248  * If it return B_TRUE it also means that all the locks we were holding
4839acbbeafSnn35248  * were dropped so that we could send the signal.
4849acbbeafSnn35248  */
4859acbbeafSnn35248 static boolean_t
freectty_signal(proc_t * p,sess_t * sp,stdata_t * stp,boolean_t at_exit)4869acbbeafSnn35248 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
4879acbbeafSnn35248 {
4889acbbeafSnn35248 	/* Assert that we hold all the necessary locks. */
4899acbbeafSnn35248 	ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
4909acbbeafSnn35248 	    MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
4919acbbeafSnn35248 
4929acbbeafSnn35248 	/* check if we already signaled this group */
4939acbbeafSnn35248 	if (sp->s_sighuped)
4949acbbeafSnn35248 		return (B_FALSE);
4959acbbeafSnn35248 
4969acbbeafSnn35248 	sp->s_sighuped = B_TRUE;
4979acbbeafSnn35248 
4989acbbeafSnn35248 	if (!at_exit) {
4999acbbeafSnn35248 		/*
5009acbbeafSnn35248 		 * once again, we're about to drop our army of locks and we
5019acbbeafSnn35248 		 * don't want sp or stp to be freed.  (see the comment in
5029acbbeafSnn35248 		 * freectty_lock())
5039acbbeafSnn35248 		 */
5049acbbeafSnn35248 		sp->s_ref++;	/* hold the session structure */
5059acbbeafSnn35248 		sp->s_cnt++;	/* protect vp and stp */
5069acbbeafSnn35248 	}
5079acbbeafSnn35248 
5089acbbeafSnn35248 	/* can't hold these locks while calling pgsignal() */
5099acbbeafSnn35248 	mutex_exit(&sp->s_lock);
5109acbbeafSnn35248 	mutex_exit(&p->p_splock);
5119acbbeafSnn35248 	mutex_exit(&pidlock);
5129acbbeafSnn35248 
5139acbbeafSnn35248 	/* signal anyone in the foreground process group */
5149acbbeafSnn35248 	pgsignal(stp->sd_pgidp, SIGHUP);
5159acbbeafSnn35248 
5169acbbeafSnn35248 	/* signal anyone blocked in poll on this stream */
5179acbbeafSnn35248 	if (!(stp->sd_flag & STRHUP))
5189acbbeafSnn35248 		strhup(stp);
5199acbbeafSnn35248 
5209acbbeafSnn35248 	mutex_exit(&stp->sd_lock);
5219acbbeafSnn35248 
5229acbbeafSnn35248 	/* release our holds */
5239acbbeafSnn35248 	if (!at_exit)
5249acbbeafSnn35248 		tty_rele(sp);
5259acbbeafSnn35248 
5269acbbeafSnn35248 	return (B_TRUE);
5279acbbeafSnn35248 }
5289acbbeafSnn35248 
5299acbbeafSnn35248 int
freectty(boolean_t at_exit)5309acbbeafSnn35248 freectty(boolean_t at_exit)
5319acbbeafSnn35248 {
5329acbbeafSnn35248 	proc_t		*p = curproc;
5339acbbeafSnn35248 	stdata_t	*stp;
5349acbbeafSnn35248 	vnode_t		*vp;
5359acbbeafSnn35248 	cred_t		*cred;
5369acbbeafSnn35248 	sess_t		*sp;
5379acbbeafSnn35248 	struct pid	*pgidp, *sidp;
5389acbbeafSnn35248 	boolean_t	got_sig = B_FALSE;
5399acbbeafSnn35248 
5409acbbeafSnn35248 	/*
5419acbbeafSnn35248 	 * If the current process is a session leader we are going to
5429acbbeafSnn35248 	 * try to release the ctty associated our current session.  To
543*da6c28aaSamw 	 * do this we need to acquire a bunch of locks, signal any
5449acbbeafSnn35248 	 * processes in the forground that are associated with the ctty,
5459acbbeafSnn35248 	 * and make sure no one has any outstanding holds on the current
546*da6c28aaSamw 	 * session * structure (acquired via tty_hold()).  Hence, we have
5479acbbeafSnn35248 	 * the following for(;;) loop that will do all this work for
5489acbbeafSnn35248 	 * us and break out when the hold count on the session structure
5499acbbeafSnn35248 	 * hits zero.
5509acbbeafSnn35248 	 */
5519acbbeafSnn35248 	for (;;) {
5529acbbeafSnn35248 		if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
5539acbbeafSnn35248 			return (EIO);
5549acbbeafSnn35248 
5559acbbeafSnn35248 		if (freectty_signal(p, sp, stp, at_exit)) {
556*da6c28aaSamw 			/* loop around to re-acquire locks */
5579acbbeafSnn35248 			continue;
5589acbbeafSnn35248 		}
5599acbbeafSnn35248 
5609acbbeafSnn35248 		/*
5619acbbeafSnn35248 		 * Only a session leader process can free a ctty.  So if
5629acbbeafSnn35248 		 * we've made it here we know we're a session leader and
5639acbbeafSnn35248 		 * if we're not actively exiting it impossible for another
5649acbbeafSnn35248 		 * thread in this process to be exiting.  (Because that
5659acbbeafSnn35248 		 * thread would have already stopped all other threads
5669acbbeafSnn35248 		 * in the current process.)
5679acbbeafSnn35248 		 */
5689acbbeafSnn35248 		ASSERT(at_exit || !sp->s_exit);
5699acbbeafSnn35248 
5709acbbeafSnn35248 		/*
5719acbbeafSnn35248 		 * If no one else has a hold on this session structure
5729acbbeafSnn35248 		 * then we now have exclusive access to it, so break out
5739acbbeafSnn35248 		 * of this loop and update the session structure.
5749acbbeafSnn35248 		 */
5759acbbeafSnn35248 		if (sp->s_cnt == 0)
5769acbbeafSnn35248 			break;
5779acbbeafSnn35248 
5789acbbeafSnn35248 		if (!at_exit) {
5799acbbeafSnn35248 			/* need to hold the session so it can't be freed */
5809acbbeafSnn35248 			sp->s_ref++;
5819acbbeafSnn35248 		}
5829acbbeafSnn35248 
5839acbbeafSnn35248 		/* ain't locking order fun? */
5849acbbeafSnn35248 		mutex_exit(&p->p_splock);
5859acbbeafSnn35248 		mutex_exit(&pidlock);
5869acbbeafSnn35248 		mutex_exit(&stp->sd_lock);
5879acbbeafSnn35248 
5889acbbeafSnn35248 		if (at_exit) {
5899acbbeafSnn35248 			/*
5909acbbeafSnn35248 			 * if we're exiting then we can't allow this operation
5919acbbeafSnn35248 			 * to fail so we do a cw_wait() instead of a
5929acbbeafSnn35248 			 * cv_wait_sig().  if there are threads with active
5939acbbeafSnn35248 			 * holds on this ctty that are blocked, then
5949acbbeafSnn35248 			 * they should only be blocked in a cv_wait_sig()
5959acbbeafSnn35248 			 * and hopefully they were in the foreground process
5969acbbeafSnn35248 			 * group and recieved the SIGHUP we sent above.  of
5979acbbeafSnn35248 			 * course it's possible that they weren't in the
5989acbbeafSnn35248 			 * foreground process group and didn't get our
5999acbbeafSnn35248 			 * signal (or they could be stopped by job control
6009acbbeafSnn35248 			 * in which case our signal wouldn't matter until
6019acbbeafSnn35248 			 * they are restarted).  in this case we won't
6029acbbeafSnn35248 			 * exit until someone else sends them a signal.
6039acbbeafSnn35248 			 */
6049acbbeafSnn35248 			cv_wait(&sp->s_cnt_cv, &sp->s_lock);
6059acbbeafSnn35248 			mutex_exit(&sp->s_lock);
6069acbbeafSnn35248 			continue;
6079acbbeafSnn35248 		}
6089acbbeafSnn35248 
6099acbbeafSnn35248 		if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
6109acbbeafSnn35248 			got_sig = B_TRUE;
6119acbbeafSnn35248 		}
6129acbbeafSnn35248 
6139acbbeafSnn35248 		mutex_exit(&sp->s_lock);
6149acbbeafSnn35248 		sess_rele(sp, B_FALSE);
6159acbbeafSnn35248 
6169acbbeafSnn35248 		if (got_sig)
6179acbbeafSnn35248 			return (EINTR);
6189acbbeafSnn35248 	}
6199acbbeafSnn35248 	ASSERT(sp->s_cnt == 0);
6209acbbeafSnn35248 
6219acbbeafSnn35248 	/* save some pointers for later */
6229acbbeafSnn35248 	cred = sp->s_cred;
6239acbbeafSnn35248 	pgidp = stp->sd_pgidp;
6249acbbeafSnn35248 	sidp = stp->sd_sidp;
6259acbbeafSnn35248 
6269acbbeafSnn35248 	/* clear the session ctty bindings */
6279acbbeafSnn35248 	sess_ctty_clear(sp, stp);
6289acbbeafSnn35248 
6299acbbeafSnn35248 	/* wake up anyone blocked in tty_hold() */
6309acbbeafSnn35248 	if (at_exit) {
6319acbbeafSnn35248 		ASSERT(sp->s_exit);
6329acbbeafSnn35248 		sp->s_exit = B_FALSE;
6339acbbeafSnn35248 		cv_broadcast(&sp->s_exit_cv);
6349acbbeafSnn35248 	}
6359acbbeafSnn35248 
6369acbbeafSnn35248 	/* we can drop these locks now */
6379acbbeafSnn35248 	mutex_exit(&sp->s_lock);
6389acbbeafSnn35248 	mutex_exit(&p->p_splock);
6399acbbeafSnn35248 	mutex_exit(&pidlock);
6409acbbeafSnn35248 	mutex_exit(&stp->sd_lock);
6419acbbeafSnn35248 
6429acbbeafSnn35248 	/* This is the only remaining thread with access to this vnode */
643*da6c28aaSamw 	(void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
6447c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
6457c478bd9Sstevel@tonic-gate 	crfree(cred);
6469acbbeafSnn35248 
6479acbbeafSnn35248 	/* release our holds on assorted structures and return */
6489acbbeafSnn35248 	mutex_enter(&pidlock);
6499acbbeafSnn35248 	PID_RELE(pgidp);
6509acbbeafSnn35248 	PID_RELE(sidp);
6519acbbeafSnn35248 	mutex_exit(&pidlock);
6529acbbeafSnn35248 
6539acbbeafSnn35248 	return (1);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate /*
6577c478bd9Sstevel@tonic-gate  *	++++++++++++++++++++++++
6587c478bd9Sstevel@tonic-gate  *	++  SunOS4.1 Buyback  ++
6597c478bd9Sstevel@tonic-gate  *	++++++++++++++++++++++++
6607c478bd9Sstevel@tonic-gate  *
6617c478bd9Sstevel@tonic-gate  * vhangup: Revoke access of the current tty by all processes
6627c478bd9Sstevel@tonic-gate  * Used by privileged users to give a "clean" terminal at login
6637c478bd9Sstevel@tonic-gate  */
6647c478bd9Sstevel@tonic-gate int
vhangup(void)665ad1660d0Smeem vhangup(void)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
6687c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
6697c478bd9Sstevel@tonic-gate 	/*
6707c478bd9Sstevel@tonic-gate 	 * This routine used to call freectty() under a condition that
6717c478bd9Sstevel@tonic-gate 	 * could never happen.  So this code has never actually done
672ad1660d0Smeem 	 * anything, and evidently nobody has ever noticed.
6737c478bd9Sstevel@tonic-gate 	 */
6747c478bd9Sstevel@tonic-gate 	return (0);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate dev_t
cttydev(proc_t * pp)6787c478bd9Sstevel@tonic-gate cttydev(proc_t *pp)
6797c478bd9Sstevel@tonic-gate {
6809acbbeafSnn35248 	sess_t	*sp;
6819acbbeafSnn35248 	dev_t	dev;
6829acbbeafSnn35248 
6839acbbeafSnn35248 	mutex_enter(&pp->p_splock);	/* protects p->p_sessp */
6849acbbeafSnn35248 	sp = pp->p_sessp;
6859acbbeafSnn35248 
6869acbbeafSnn35248 #ifdef DEBUG
6879acbbeafSnn35248 	mutex_enter(&sp->s_lock);	/* protects sp->* */
6887c478bd9Sstevel@tonic-gate 	if (sp->s_vp == NULL)
6899acbbeafSnn35248 		ASSERT(sp->s_dev == NODEV);
6909acbbeafSnn35248 	else
6919acbbeafSnn35248 		ASSERT(sp->s_dev != NODEV);
6929acbbeafSnn35248 	mutex_exit(&sp->s_lock);
6939acbbeafSnn35248 #endif /* DEBUG */
6949acbbeafSnn35248 
6959acbbeafSnn35248 	dev = sp->s_dev;
6969acbbeafSnn35248 	mutex_exit(&pp->p_splock);
6979acbbeafSnn35248 	return (dev);
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate void
ctty_clear_sighuped(void)7019acbbeafSnn35248 ctty_clear_sighuped(void)
7027c478bd9Sstevel@tonic-gate {
7039acbbeafSnn35248 	ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
7049acbbeafSnn35248 	curproc->p_sessp->s_sighuped = B_FALSE;
7057c478bd9Sstevel@tonic-gate }
706