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
59acbbeafSnn * Common Development and Distribution License (the "License").
69acbbeafSnn * 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>
469acbbeafSnn #include <sys/fs/snode.h>
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate sess_t session0 = {
499acbbeafSnn &pid0, /* s_sidp */
509acbbeafSnn {0}, /* s_lock */
519acbbeafSnn 1, /* s_ref */
529acbbeafSnn B_FALSE, /* s_sighuped */
539acbbeafSnn B_FALSE, /* s_exit */
549acbbeafSnn 0, /* s_exit_cv */
559acbbeafSnn 0, /* s_cnt */
569acbbeafSnn 0, /* s_cnt_cv */
579acbbeafSnn NODEV, /* s_dev */
589acbbeafSnn NULL, /* s_vp */
599acbbeafSnn NULL /* s_cred */
607c478bd9Sstevel@tonic-gate };
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate void
sess_hold(proc_t * p)639acbbeafSnn sess_hold(proc_t *p)
647c478bd9Sstevel@tonic-gate {
659acbbeafSnn ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
669acbbeafSnn mutex_enter(&p->p_sessp->s_lock);
679acbbeafSnn p->p_sessp->s_ref++;
689acbbeafSnn mutex_exit(&p->p_sessp->s_lock);
699acbbeafSnn }
709acbbeafSnn
719acbbeafSnn void
sess_rele(sess_t * sp,boolean_t pidlock_held)729acbbeafSnn sess_rele(sess_t *sp, boolean_t pidlock_held)
739acbbeafSnn {
749acbbeafSnn ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
759acbbeafSnn
769acbbeafSnn mutex_enter(&sp->s_lock);
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate ASSERT(sp->s_ref != 0);
799acbbeafSnn if (--sp->s_ref > 0) {
809acbbeafSnn mutex_exit(&sp->s_lock);
819acbbeafSnn return;
827c478bd9Sstevel@tonic-gate }
839acbbeafSnn ASSERT(sp->s_ref == 0);
849acbbeafSnn
859acbbeafSnn /*
869acbbeafSnn * It's ok to free this session structure now because we know
879acbbeafSnn * that no one else can have a pointer to it. We know this
889acbbeafSnn * to be true because the only time that s_ref can possibly
899acbbeafSnn * be incremented is when pidlock or p_splock is held AND there
909acbbeafSnn * is a proc_t that points to that session structure. In that
919acbbeafSnn * case we are guaranteed that the s_ref is at least 1 since there
929acbbeafSnn * is a proc_t that points to it. So when s_ref finally drops to
939acbbeafSnn * zero then no one else has a reference (and hence pointer) to
949acbbeafSnn * this session structure and there is no valid proc_t pointing
959acbbeafSnn * to this session structure anymore so, no one can acquire a
969acbbeafSnn * reference (and pointer) to this session structure so it's
979acbbeafSnn * ok to free it here.
989acbbeafSnn */
999acbbeafSnn
1009acbbeafSnn if (sp == &session0)
1019acbbeafSnn panic("sp == &session0");
1029acbbeafSnn
1039acbbeafSnn /* make sure there are no outstanding holds */
1049acbbeafSnn ASSERT(sp->s_cnt == 0);
1059acbbeafSnn
1069acbbeafSnn /* make sure there is no exit in progress */
1079acbbeafSnn ASSERT(!sp->s_exit);
1089acbbeafSnn
1099acbbeafSnn /* make sure someone already freed any ctty */
1109acbbeafSnn ASSERT(sp->s_vp == NULL);
1119acbbeafSnn ASSERT(sp->s_dev == NODEV);
1129acbbeafSnn
1139acbbeafSnn if (!pidlock_held)
1149acbbeafSnn mutex_enter(&pidlock);
1159acbbeafSnn PID_RELE(sp->s_sidp);
1169acbbeafSnn if (!pidlock_held)
1179acbbeafSnn mutex_exit(&pidlock);
1189acbbeafSnn
1199acbbeafSnn mutex_destroy(&sp->s_lock);
1209acbbeafSnn cv_destroy(&sp->s_cnt_cv);
1219acbbeafSnn kmem_free(sp, sizeof (sess_t));
1229acbbeafSnn }
1239acbbeafSnn
1249acbbeafSnn sess_t *
tty_hold(void)1259acbbeafSnn tty_hold(void)
1269acbbeafSnn {
1279acbbeafSnn proc_t *p = curproc;
1289acbbeafSnn sess_t *sp;
1299acbbeafSnn boolean_t got_sig = B_FALSE;
1309acbbeafSnn
1319acbbeafSnn /* make sure the caller isn't holding locks they shouldn't */
1329acbbeafSnn ASSERT(MUTEX_NOT_HELD(&pidlock));
1339acbbeafSnn
1349acbbeafSnn for (;;) {
1359acbbeafSnn mutex_enter(&p->p_splock); /* protect p->p_sessp */
1369acbbeafSnn sp = p->p_sessp;
1379acbbeafSnn mutex_enter(&sp->s_lock); /* protect sp->* */
1389acbbeafSnn
1399acbbeafSnn /* make sure the caller isn't holding locks they shouldn't */
1409acbbeafSnn ASSERT((sp->s_vp == NULL) ||
1419acbbeafSnn MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
1429acbbeafSnn
1439acbbeafSnn /*
1449acbbeafSnn * If the session leader process is not exiting (and hence
1459acbbeafSnn * not trying to release the session's ctty) then we can
1469acbbeafSnn * safely grab a hold on the current session structure
1479acbbeafSnn * and return it. If on the other hand the session leader
1489acbbeafSnn * process is exiting and clearing the ctty then we'll
1499acbbeafSnn * wait till it's done before we loop around and grab a
1509acbbeafSnn * hold on the session structure.
1519acbbeafSnn */
1529acbbeafSnn if (!sp->s_exit)
1539acbbeafSnn break;
1549acbbeafSnn
1559acbbeafSnn /* need to hold the session so it can't be freed */
1569acbbeafSnn sp->s_ref++;
1579acbbeafSnn mutex_exit(&p->p_splock);
1589acbbeafSnn
1599acbbeafSnn /* Wait till the session leader is done */
1609acbbeafSnn if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
1619acbbeafSnn got_sig = B_TRUE;
1629acbbeafSnn
1639acbbeafSnn /*
1649acbbeafSnn * Now we need to drop our hold on the session structure,
1659acbbeafSnn * but we can't hold any locks when we do this because
166*da6c28aaSamw * sess_rele() may need to acquire pidlock.
1679acbbeafSnn */
1689acbbeafSnn mutex_exit(&sp->s_lock);
1699acbbeafSnn sess_rele(sp, B_FALSE);
1709acbbeafSnn
1719acbbeafSnn if (got_sig)
1729acbbeafSnn return (NULL);
1739acbbeafSnn }
1749acbbeafSnn
1759acbbeafSnn /* whew, we finally got a hold */
1769acbbeafSnn sp->s_cnt++;
1779acbbeafSnn sp->s_ref++;
1789acbbeafSnn mutex_exit(&sp->s_lock);
1799acbbeafSnn mutex_exit(&p->p_splock);
1809acbbeafSnn return (sp);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate void
tty_rele(sess_t * sp)1849acbbeafSnn tty_rele(sess_t *sp)
1857c478bd9Sstevel@tonic-gate {
1869acbbeafSnn /* make sure the caller isn't holding locks they shouldn't */
1879acbbeafSnn ASSERT(MUTEX_NOT_HELD(&pidlock));
1887c478bd9Sstevel@tonic-gate
1899acbbeafSnn mutex_enter(&sp->s_lock);
1909acbbeafSnn if ((--sp->s_cnt) == 0)
1919acbbeafSnn cv_broadcast(&sp->s_cnt_cv);
1929acbbeafSnn mutex_exit(&sp->s_lock);
1939acbbeafSnn
1949acbbeafSnn sess_rele(sp, B_FALSE);
1959acbbeafSnn }
1969acbbeafSnn
1979acbbeafSnn void
sess_create(void)1989acbbeafSnn sess_create(void)
1999acbbeafSnn {
2009acbbeafSnn proc_t *p = curproc;
2019acbbeafSnn 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);
2069acbbeafSnn cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
2077c478bd9Sstevel@tonic-gate
2089acbbeafSnn /*
2099acbbeafSnn * we need to grap p_lock to protect p_pgidp because
2109acbbeafSnn * /proc looks at p_pgidp while holding only p_lock.
2119acbbeafSnn *
2129acbbeafSnn * we don't need to hold p->p_sessp->s_lock or get a hold on the
2139acbbeafSnn * session structure since we're not actually updating any of
2149acbbeafSnn * the contents of the old session structure.
2159acbbeafSnn */
2167c478bd9Sstevel@tonic-gate mutex_enter(&pidlock);
2179acbbeafSnn mutex_enter(&p->p_lock);
2189acbbeafSnn mutex_enter(&p->p_splock);
2199acbbeafSnn
2209acbbeafSnn pgexit(p);
2219acbbeafSnn
2229acbbeafSnn sp->s_sidp = p->p_pidp;
2239acbbeafSnn sp->s_ref = 1;
2249acbbeafSnn sp->s_dev = NODEV;
2259acbbeafSnn
2269acbbeafSnn old_sp = p->p_sessp;
2279acbbeafSnn p->p_sessp = sp;
2289acbbeafSnn
2299acbbeafSnn pgjoin(p, p->p_pidp);
2309acbbeafSnn PID_HOLD(p->p_pidp);
2319acbbeafSnn
2329acbbeafSnn mutex_exit(&p->p_splock);
2339acbbeafSnn mutex_exit(&p->p_lock);
2349acbbeafSnn mutex_exit(&pidlock);
2357c478bd9Sstevel@tonic-gate
2369acbbeafSnn sess_rele(old_sp, B_FALSE);
2379acbbeafSnn }
2389acbbeafSnn
2399acbbeafSnn /*
2409acbbeafSnn * Note that sess_ctty_clear() resets all the fields in the session
2419acbbeafSnn * structure but doesn't release any holds or free any objects
2429acbbeafSnn * that the session structure might currently point to. it is the
2439acbbeafSnn * callers responsibility to do this.
2449acbbeafSnn */
2459acbbeafSnn static void
sess_ctty_clear(sess_t * sp,stdata_t * stp)2469acbbeafSnn sess_ctty_clear(sess_t *sp, stdata_t *stp)
2479acbbeafSnn {
2487c478bd9Sstevel@tonic-gate /*
2499acbbeafSnn * Assert that we hold all the necessary locks. We also need
2509acbbeafSnn * to be holding proc_t->p_splock for the process associated
2519acbbeafSnn * with this session, but since we don't have a proc pointer
2529acbbeafSnn * passed in we can't assert this here.
2537c478bd9Sstevel@tonic-gate */
2549acbbeafSnn ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2559acbbeafSnn MUTEX_HELD(&sp->s_lock));
2567c478bd9Sstevel@tonic-gate
2579acbbeafSnn /* reset the session structure members to defaults */
2589acbbeafSnn sp->s_sighuped = B_FALSE;
2597c478bd9Sstevel@tonic-gate sp->s_dev = NODEV;
2609acbbeafSnn sp->s_vp = NULL;
2619acbbeafSnn sp->s_cred = NULL;
2629acbbeafSnn
2639acbbeafSnn /* reset the stream session and group pointers */
2649acbbeafSnn stp->sd_pgidp = NULL;
2659acbbeafSnn stp->sd_sidp = NULL;
2669acbbeafSnn }
2679acbbeafSnn
2689acbbeafSnn static void
sess_ctty_set(proc_t * p,sess_t * sp,stdata_t * stp)2699acbbeafSnn sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
2709acbbeafSnn {
2719acbbeafSnn cred_t *crp;
2729acbbeafSnn
2739acbbeafSnn /* Assert that we hold all the necessary locks. */
2749acbbeafSnn ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2759acbbeafSnn MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
2769acbbeafSnn
2779acbbeafSnn /* get holds on structures */
2789acbbeafSnn mutex_enter(&p->p_crlock);
2799acbbeafSnn crhold(crp = p->p_cred);
2809acbbeafSnn mutex_exit(&p->p_crlock);
2819acbbeafSnn PID_HOLD(sp->s_sidp); /* requires pidlock */
2829acbbeafSnn PID_HOLD(sp->s_sidp); /* requires pidlock */
2839acbbeafSnn
2849acbbeafSnn /* update the session structure members */
2859acbbeafSnn sp->s_vp = makectty(stp->sd_vnode);
2869acbbeafSnn sp->s_dev = sp->s_vp->v_rdev;
2879acbbeafSnn sp->s_cred = crp;
2889acbbeafSnn
2899acbbeafSnn /* update the stream emebers */
2909acbbeafSnn stp->sd_flag |= STRISTTY; /* just to be sure */
2919acbbeafSnn stp->sd_sidp = sp->s_sidp;
2929acbbeafSnn stp->sd_pgidp = sp->s_sidp;
2939acbbeafSnn }
2949acbbeafSnn
2959acbbeafSnn int
strctty(stdata_t * stp)2969acbbeafSnn strctty(stdata_t *stp)
2979acbbeafSnn {
2989acbbeafSnn sess_t *sp;
2999acbbeafSnn proc_t *p = curproc;
3009acbbeafSnn boolean_t got_sig = B_FALSE;
3019acbbeafSnn
3029acbbeafSnn /*
3039acbbeafSnn * We are going to try to make stp the default ctty for the session
3049acbbeafSnn * associated with curproc. Not only does this require holding a
3059acbbeafSnn * bunch of locks but it also requires waiting for any outstanding
306*da6c28aaSamw * holds on the session structure (acquired via tty_hold()) to be
3079acbbeafSnn * released. Hence, we have the following for(;;) loop that will
308*da6c28aaSamw * acquire our locks, do some sanity checks, and wait for the hold
3099acbbeafSnn * count on the session structure to hit zero. If we get a signal
3109acbbeafSnn * while waiting for outstanding holds to be released then we abort
3119acbbeafSnn * the operation and return.
3129acbbeafSnn */
3139acbbeafSnn for (;;) {
3149acbbeafSnn mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
3159acbbeafSnn mutex_enter(&pidlock); /* protects p_pidp */
3169acbbeafSnn mutex_enter(&p->p_splock); /* protects p_sessp */
3179acbbeafSnn sp = p->p_sessp;
3189acbbeafSnn mutex_enter(&sp->s_lock); /* protects sp->* */
3199acbbeafSnn
3209acbbeafSnn if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
3219acbbeafSnn (stp->sd_sidp != NULL) || /* stp already ctty? */
3229acbbeafSnn (p->p_pidp != sp->s_sidp) || /* we're not leader? */
3239acbbeafSnn (sp->s_vp != NULL)) { /* session has ctty? */
3249acbbeafSnn mutex_exit(&sp->s_lock);
3259acbbeafSnn mutex_exit(&p->p_splock);
3269acbbeafSnn mutex_exit(&pidlock);
3279acbbeafSnn mutex_exit(&stp->sd_lock);
3289acbbeafSnn return (ENOTTY);
3299acbbeafSnn }
3309acbbeafSnn
3319acbbeafSnn /* sanity check. we can't be exiting right now */
3329acbbeafSnn ASSERT(!sp->s_exit);
3339acbbeafSnn
3349acbbeafSnn /*
3359acbbeafSnn * If no one else has a hold on this session structure
3369acbbeafSnn * then we now have exclusive access to it, so break out
3379acbbeafSnn * of this loop and update the session structure.
3389acbbeafSnn */
3399acbbeafSnn if (sp->s_cnt == 0)
3409acbbeafSnn break;
3419acbbeafSnn
3429acbbeafSnn /* need to hold the session so it can't be freed */
3439acbbeafSnn sp->s_ref++;
3447c478bd9Sstevel@tonic-gate
3459acbbeafSnn /* ain't locking order fun? */
3469acbbeafSnn mutex_exit(&p->p_splock);
3479acbbeafSnn mutex_exit(&pidlock);
3489acbbeafSnn mutex_exit(&stp->sd_lock);
3497c478bd9Sstevel@tonic-gate
3509acbbeafSnn if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
3519acbbeafSnn got_sig = B_TRUE;
3529acbbeafSnn mutex_exit(&sp->s_lock);
3539acbbeafSnn sess_rele(sp, B_FALSE);
3547c478bd9Sstevel@tonic-gate
3559acbbeafSnn if (got_sig)
3569acbbeafSnn return (EINTR);
3579acbbeafSnn }
3589acbbeafSnn
3599acbbeafSnn /* set the session ctty bindings */
3609acbbeafSnn sess_ctty_set(p, sp, stp);
3619acbbeafSnn
3629acbbeafSnn mutex_exit(&sp->s_lock);
3639acbbeafSnn mutex_exit(&p->p_splock);
3647c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
3659acbbeafSnn mutex_exit(&stp->sd_lock);
3669acbbeafSnn return (0);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate
3699acbbeafSnn /*
370*da6c28aaSamw * freectty_lock() attempts to acquire the army of locks required to free
3719acbbeafSnn * the ctty associated with a given session leader process. If it returns
3729acbbeafSnn * successfully the following locks will be held:
3739acbbeafSnn * sd_lock, pidlock, p_splock, s_lock
3749acbbeafSnn *
375*da6c28aaSamw * as a secondary bit of convenience, freectty_lock() will also return
3769acbbeafSnn * pointers to the session, ctty, and ctty stream associated with the
3779acbbeafSnn * specified session leader process.
3789acbbeafSnn */
3799acbbeafSnn static boolean_t
freectty_lock(proc_t * p,sess_t ** spp,vnode_t ** vpp,stdata_t ** stpp,boolean_t at_exit)3809acbbeafSnn freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
3819acbbeafSnn boolean_t at_exit)
3827c478bd9Sstevel@tonic-gate {
3839acbbeafSnn sess_t *sp;
3849acbbeafSnn vnode_t *vp;
3859acbbeafSnn stdata_t *stp;
3867c478bd9Sstevel@tonic-gate
3879acbbeafSnn mutex_enter(&pidlock); /* protect p_pidp */
3889acbbeafSnn mutex_enter(&p->p_splock); /* protect p->p_sessp */
3899acbbeafSnn sp = p->p_sessp;
3909acbbeafSnn mutex_enter(&sp->s_lock); /* protect sp->* */
3917c478bd9Sstevel@tonic-gate
3929acbbeafSnn if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */
3939acbbeafSnn (sp->s_vp == NULL)) { /* no ctty? */
3949acbbeafSnn mutex_exit(&sp->s_lock);
3959acbbeafSnn mutex_exit(&p->p_splock);
3969acbbeafSnn mutex_exit(&pidlock);
3979acbbeafSnn return (B_FALSE);
3989acbbeafSnn }
3999acbbeafSnn
4009acbbeafSnn vp = sp->s_vp;
4019acbbeafSnn stp = sp->s_vp->v_stream;
4029acbbeafSnn
4039acbbeafSnn if (at_exit) {
4049acbbeafSnn /* stop anyone else calling tty_hold() */
4059acbbeafSnn sp->s_exit = B_TRUE;
4069acbbeafSnn } else {
4079acbbeafSnn /*
4089acbbeafSnn * due to locking order we have to grab stp->sd_lock before
4099acbbeafSnn * grabbing all the other proc/session locks. but after we
4109acbbeafSnn * drop all our current locks it's possible that someone
4119acbbeafSnn * could come in and change our current session or close
4129acbbeafSnn * the current ctty (vp) there by making sp or stp invalid.
4139acbbeafSnn * (a VN_HOLD on vp won't protect stp because that only
4149acbbeafSnn * prevents the vnode from being freed not closed.) so
4159acbbeafSnn * to prevent this we bump s_ref and s_cnt here.
4169acbbeafSnn *
4179acbbeafSnn * course this doesn't matter if we're the last thread in
4189acbbeafSnn * an exiting process that is the session leader, since no
4199acbbeafSnn * one else can change our session or free our ctty.
4209acbbeafSnn */
4219acbbeafSnn sp->s_ref++; /* hold the session structure */
4229acbbeafSnn sp->s_cnt++; /* protect vp and stp */
4239acbbeafSnn }
4249acbbeafSnn
4259acbbeafSnn /* drop our session locks */
4269acbbeafSnn mutex_exit(&sp->s_lock);
4279acbbeafSnn mutex_exit(&p->p_splock);
4289acbbeafSnn mutex_exit(&pidlock);
4299acbbeafSnn
4309acbbeafSnn /* grab locks in the right order */
4319acbbeafSnn mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
4329acbbeafSnn mutex_enter(&pidlock); /* protect p_pidp */
4339acbbeafSnn mutex_enter(&p->p_splock); /* protects p->p_sessp */
4349acbbeafSnn mutex_enter(&sp->s_lock); /* protects sp->* */
4359acbbeafSnn
4369acbbeafSnn /* if the session has changed, abort mission */
4379acbbeafSnn if (sp != p->p_sessp) {
4389acbbeafSnn /*
4399acbbeafSnn * this can't happen during process exit since we're the
4409acbbeafSnn * only thread in the process and we sure didn't change
4419acbbeafSnn * our own session at this point.
4429acbbeafSnn */
4439acbbeafSnn ASSERT(!at_exit);
4449acbbeafSnn
4459acbbeafSnn /* release our locks and holds */
4469acbbeafSnn mutex_exit(&sp->s_lock);
4479acbbeafSnn mutex_exit(&p->p_splock);
4489acbbeafSnn mutex_exit(&pidlock);
4499acbbeafSnn mutex_exit(&stp->sd_lock);
4509acbbeafSnn tty_rele(sp);
4519acbbeafSnn return (B_FALSE);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate /*
4559acbbeafSnn * sanity checks. none of this should have changed since we had
4569acbbeafSnn * holds on the current ctty.
4577c478bd9Sstevel@tonic-gate */
4589acbbeafSnn ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */
4599acbbeafSnn ASSERT(sp->s_vp != NULL); /* a ctty exists */
4609acbbeafSnn ASSERT(vp == sp->s_vp);
4619acbbeafSnn ASSERT(stp == sp->s_vp->v_stream);
4629acbbeafSnn
4639acbbeafSnn /* release our holds */
4649acbbeafSnn if (!at_exit) {
4659acbbeafSnn if ((--(sp)->s_cnt) == 0)
4669acbbeafSnn cv_broadcast(&sp->s_cnt_cv);
4679acbbeafSnn sp->s_ref--;
4689acbbeafSnn ASSERT(sp->s_ref > 0);
4699acbbeafSnn }
4709acbbeafSnn
4719acbbeafSnn /* return our pointers */
4729acbbeafSnn *spp = sp;
4739acbbeafSnn *vpp = vp;
4749acbbeafSnn *stpp = stp;
4757c478bd9Sstevel@tonic-gate
4769acbbeafSnn return (B_TRUE);
4779acbbeafSnn }
4789acbbeafSnn
4799acbbeafSnn /*
4809acbbeafSnn * Returns B_FALSE if no signal is sent to the process group associated with
4819acbbeafSnn * this ctty. Returns B_TRUE if a signal is sent to the process group.
4829acbbeafSnn * If it return B_TRUE it also means that all the locks we were holding
4839acbbeafSnn * were dropped so that we could send the signal.
4849acbbeafSnn */
4859acbbeafSnn static boolean_t
freectty_signal(proc_t * p,sess_t * sp,stdata_t * stp,boolean_t at_exit)4869acbbeafSnn freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
4879acbbeafSnn {
4889acbbeafSnn /* Assert that we hold all the necessary locks. */
4899acbbeafSnn ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
4909acbbeafSnn MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
4919acbbeafSnn
4929acbbeafSnn /* check if we already signaled this group */
4939acbbeafSnn if (sp->s_sighuped)
4949acbbeafSnn return (B_FALSE);
4959acbbeafSnn
4969acbbeafSnn sp->s_sighuped = B_TRUE;
4979acbbeafSnn
4989acbbeafSnn if (!at_exit) {
4999acbbeafSnn /*
5009acbbeafSnn * once again, we're about to drop our army of locks and we
5019acbbeafSnn * don't want sp or stp to be freed. (see the comment in
5029acbbeafSnn * freectty_lock())
5039acbbeafSnn */
5049acbbeafSnn sp->s_ref++; /* hold the session structure */
5059acbbeafSnn sp->s_cnt++; /* protect vp and stp */
5069acbbeafSnn }
5079acbbeafSnn
5089acbbeafSnn /* can't hold these locks while calling pgsignal() */
5097c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock);
5109acbbeafSnn mutex_exit(&p->p_splock);
5119acbbeafSnn mutex_exit(&pidlock);
5129acbbeafSnn
5139acbbeafSnn /* signal anyone in the foreground process group */
5149acbbeafSnn pgsignal(stp->sd_pgidp, SIGHUP);
5159acbbeafSnn
5169acbbeafSnn /* signal anyone blocked in poll on this stream */
5179acbbeafSnn if (!(stp->sd_flag & STRHUP))
5189acbbeafSnn strhup(stp);
5199acbbeafSnn
5209acbbeafSnn mutex_exit(&stp->sd_lock);
5219acbbeafSnn
5229acbbeafSnn /* release our holds */
5239acbbeafSnn if (!at_exit)
5249acbbeafSnn tty_rele(sp);
5259acbbeafSnn
5269acbbeafSnn return (B_TRUE);
5279acbbeafSnn }
5289acbbeafSnn
5299acbbeafSnn int
freectty(boolean_t at_exit)5309acbbeafSnn freectty(boolean_t at_exit)
5319acbbeafSnn {
5329acbbeafSnn proc_t *p = curproc;
5339acbbeafSnn stdata_t *stp;
5349acbbeafSnn vnode_t *vp;
5359acbbeafSnn cred_t *cred;
5369acbbeafSnn sess_t *sp;
5379acbbeafSnn struct pid *pgidp, *sidp;
5389acbbeafSnn boolean_t got_sig = B_FALSE;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /*
5419acbbeafSnn * If the current process is a session leader we are going to
5429acbbeafSnn * try to release the ctty associated our current session. To
543*da6c28aaSamw * do this we need to acquire a bunch of locks, signal any
5449acbbeafSnn * processes in the forground that are associated with the ctty,
5459acbbeafSnn * and make sure no one has any outstanding holds on the current
546*da6c28aaSamw * session * structure (acquired via tty_hold()). Hence, we have
5479acbbeafSnn * the following for(;;) loop that will do all this work for
5489acbbeafSnn * us and break out when the hold count on the session structure
5499acbbeafSnn * hits zero.
5507c478bd9Sstevel@tonic-gate */
5519acbbeafSnn for (;;) {
5529acbbeafSnn if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
5539acbbeafSnn return (EIO);
5549acbbeafSnn
5559acbbeafSnn if (freectty_signal(p, sp, stp, at_exit)) {
556*da6c28aaSamw /* loop around to re-acquire locks */
5579acbbeafSnn continue;
5589acbbeafSnn }
5599acbbeafSnn
5609acbbeafSnn /*
5619acbbeafSnn * Only a session leader process can free a ctty. So if
5629acbbeafSnn * we've made it here we know we're a session leader and
5639acbbeafSnn * if we're not actively exiting it impossible for another
5649acbbeafSnn * thread in this process to be exiting. (Because that
5659acbbeafSnn * thread would have already stopped all other threads
5669acbbeafSnn * in the current process.)
5679acbbeafSnn */
5689acbbeafSnn ASSERT(at_exit || !sp->s_exit);
5699acbbeafSnn
5709acbbeafSnn /*
5719acbbeafSnn * If no one else has a hold on this session structure
5729acbbeafSnn * then we now have exclusive access to it, so break out
5739acbbeafSnn * of this loop and update the session structure.
5749acbbeafSnn */
5759acbbeafSnn if (sp->s_cnt == 0)
5769acbbeafSnn break;
5779acbbeafSnn
5789acbbeafSnn if (!at_exit) {
5799acbbeafSnn /* need to hold the session so it can't be freed */
5809acbbeafSnn sp->s_ref++;
5819acbbeafSnn }
5829acbbeafSnn
5839acbbeafSnn /* ain't locking order fun? */
5849acbbeafSnn mutex_exit(&p->p_splock);
5859acbbeafSnn mutex_exit(&pidlock);
5869acbbeafSnn mutex_exit(&stp->sd_lock);
5879acbbeafSnn
5889acbbeafSnn if (at_exit) {
5899acbbeafSnn /*
5909acbbeafSnn * if we're exiting then we can't allow this operation
5919acbbeafSnn * to fail so we do a cw_wait() instead of a
5929acbbeafSnn * cv_wait_sig(). if there are threads with active
5939acbbeafSnn * holds on this ctty that are blocked, then
5949acbbeafSnn * they should only be blocked in a cv_wait_sig()
5959acbbeafSnn * and hopefully they were in the foreground process
5969acbbeafSnn * group and recieved the SIGHUP we sent above. of
5979acbbeafSnn * course it's possible that they weren't in the
5989acbbeafSnn * foreground process group and didn't get our
5999acbbeafSnn * signal (or they could be stopped by job control
6009acbbeafSnn * in which case our signal wouldn't matter until
6019acbbeafSnn * they are restarted). in this case we won't
6029acbbeafSnn * exit until someone else sends them a signal.
6039acbbeafSnn */
6049acbbeafSnn cv_wait(&sp->s_cnt_cv, &sp->s_lock);
6059acbbeafSnn mutex_exit(&sp->s_lock);
6069acbbeafSnn continue;
6079acbbeafSnn }
6089acbbeafSnn
6099acbbeafSnn if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
6109acbbeafSnn got_sig = B_TRUE;
6119acbbeafSnn }
6129acbbeafSnn
6139acbbeafSnn mutex_exit(&sp->s_lock);
6149acbbeafSnn sess_rele(sp, B_FALSE);
6159acbbeafSnn
6169acbbeafSnn if (got_sig)
6179acbbeafSnn return (EINTR);
6189acbbeafSnn }
6199acbbeafSnn ASSERT(sp->s_cnt == 0);
6207c478bd9Sstevel@tonic-gate
6219acbbeafSnn /* save some pointers for later */
6229acbbeafSnn cred = sp->s_cred;
6239acbbeafSnn pgidp = stp->sd_pgidp;
6249acbbeafSnn sidp = stp->sd_sidp;
6259acbbeafSnn
6269acbbeafSnn /* clear the session ctty bindings */
6279acbbeafSnn sess_ctty_clear(sp, stp);
6289acbbeafSnn
6299acbbeafSnn /* wake up anyone blocked in tty_hold() */
6309acbbeafSnn if (at_exit) {
6319acbbeafSnn ASSERT(sp->s_exit);
6329acbbeafSnn sp->s_exit = B_FALSE;
6339acbbeafSnn cv_broadcast(&sp->s_exit_cv);
6349acbbeafSnn }
6359acbbeafSnn
6369acbbeafSnn /* we can drop these locks now */
6379acbbeafSnn mutex_exit(&sp->s_lock);
6389acbbeafSnn mutex_exit(&p->p_splock);
6399acbbeafSnn mutex_exit(&pidlock);
6409acbbeafSnn mutex_exit(&stp->sd_lock);
6419acbbeafSnn
6429acbbeafSnn /* 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);
6469acbbeafSnn
6479acbbeafSnn /* release our holds on assorted structures and return */
6489acbbeafSnn mutex_enter(&pidlock);
6499acbbeafSnn PID_RELE(pgidp);
6509acbbeafSnn PID_RELE(sidp);
6519acbbeafSnn mutex_exit(&pidlock);
6529acbbeafSnn
6539acbbeafSnn 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 {
6809acbbeafSnn sess_t *sp;
6819acbbeafSnn dev_t dev;
6829acbbeafSnn
6839acbbeafSnn mutex_enter(&pp->p_splock); /* protects p->p_sessp */
6849acbbeafSnn sp = pp->p_sessp;
6859acbbeafSnn
6869acbbeafSnn #ifdef DEBUG
6879acbbeafSnn mutex_enter(&sp->s_lock); /* protects sp->* */
6887c478bd9Sstevel@tonic-gate if (sp->s_vp == NULL)
6899acbbeafSnn ASSERT(sp->s_dev == NODEV);
6909acbbeafSnn else
6919acbbeafSnn ASSERT(sp->s_dev != NODEV);
6929acbbeafSnn mutex_exit(&sp->s_lock);
6939acbbeafSnn #endif /* DEBUG */
6949acbbeafSnn
6959acbbeafSnn dev = sp->s_dev;
6969acbbeafSnn mutex_exit(&pp->p_splock);
6979acbbeafSnn return (dev);
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate void
ctty_clear_sighuped(void)7019acbbeafSnn ctty_clear_sighuped(void)
7027c478bd9Sstevel@tonic-gate {
7039acbbeafSnn ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
7049acbbeafSnn curproc->p_sessp->s_sighuped = B_FALSE;
7057c478bd9Sstevel@tonic-gate }
706