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 307c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <sys/systm.h> 367c478bd9Sstevel@tonic-gate #include <sys/file.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/errno.h> 397c478bd9Sstevel@tonic-gate #include <sys/signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/cred.h> 417c478bd9Sstevel@tonic-gate #include <sys/policy.h> 427c478bd9Sstevel@tonic-gate #include <sys/conf.h> 437c478bd9Sstevel@tonic-gate #include <sys/debug.h> 447c478bd9Sstevel@tonic-gate #include <sys/proc.h> 457c478bd9Sstevel@tonic-gate #include <sys/session.h> 467c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 487c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 499acbbeafSnn35248 #include <sys/fs/snode.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate sess_t session0 = { 529acbbeafSnn35248 &pid0, /* s_sidp */ 539acbbeafSnn35248 {0}, /* s_lock */ 547c478bd9Sstevel@tonic-gate 1, /* s_ref */ 559acbbeafSnn35248 B_FALSE, /* s_sighuped */ 569acbbeafSnn35248 B_FALSE, /* s_exit */ 579acbbeafSnn35248 0, /* s_exit_cv */ 589acbbeafSnn35248 0, /* s_cnt */ 599acbbeafSnn35248 0, /* s_cnt_cv */ 607c478bd9Sstevel@tonic-gate NODEV, /* s_dev */ 617c478bd9Sstevel@tonic-gate NULL, /* s_vp */ 627c478bd9Sstevel@tonic-gate NULL /* s_cred */ 637c478bd9Sstevel@tonic-gate }; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate void 669acbbeafSnn35248 sess_hold(proc_t *p) 677c478bd9Sstevel@tonic-gate { 689acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock)); 699acbbeafSnn35248 mutex_enter(&p->p_sessp->s_lock); 709acbbeafSnn35248 p->p_sessp->s_ref++; 719acbbeafSnn35248 mutex_exit(&p->p_sessp->s_lock); 729acbbeafSnn35248 } 739acbbeafSnn35248 749acbbeafSnn35248 void 759acbbeafSnn35248 sess_rele(sess_t *sp, boolean_t pidlock_held) 769acbbeafSnn35248 { 779acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held); 789acbbeafSnn35248 799acbbeafSnn35248 mutex_enter(&sp->s_lock); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate ASSERT(sp->s_ref != 0); 829acbbeafSnn35248 if (--sp->s_ref > 0) { 839acbbeafSnn35248 mutex_exit(&sp->s_lock); 849acbbeafSnn35248 return; 859acbbeafSnn35248 } 869acbbeafSnn35248 ASSERT(sp->s_ref == 0); 879acbbeafSnn35248 889acbbeafSnn35248 /* 899acbbeafSnn35248 * It's ok to free this session structure now because we know 909acbbeafSnn35248 * that no one else can have a pointer to it. We know this 919acbbeafSnn35248 * to be true because the only time that s_ref can possibly 929acbbeafSnn35248 * be incremented is when pidlock or p_splock is held AND there 939acbbeafSnn35248 * is a proc_t that points to that session structure. In that 949acbbeafSnn35248 * case we are guaranteed that the s_ref is at least 1 since there 959acbbeafSnn35248 * is a proc_t that points to it. So when s_ref finally drops to 969acbbeafSnn35248 * zero then no one else has a reference (and hence pointer) to 979acbbeafSnn35248 * this session structure and there is no valid proc_t pointing 989acbbeafSnn35248 * to this session structure anymore so, no one can acquire a 999acbbeafSnn35248 * reference (and pointer) to this session structure so it's 1009acbbeafSnn35248 * ok to free it here. 1019acbbeafSnn35248 */ 1029acbbeafSnn35248 1037c478bd9Sstevel@tonic-gate if (sp == &session0) 1047c478bd9Sstevel@tonic-gate panic("sp == &session0"); 1059acbbeafSnn35248 1069acbbeafSnn35248 /* make sure there are no outstanding holds */ 1079acbbeafSnn35248 ASSERT(sp->s_cnt == 0); 1089acbbeafSnn35248 1099acbbeafSnn35248 /* make sure there is no exit in progress */ 1109acbbeafSnn35248 ASSERT(!sp->s_exit); 1119acbbeafSnn35248 1129acbbeafSnn35248 /* make sure someone already freed any ctty */ 1139acbbeafSnn35248 ASSERT(sp->s_vp == NULL); 1149acbbeafSnn35248 ASSERT(sp->s_dev == NODEV); 1159acbbeafSnn35248 1169acbbeafSnn35248 if (!pidlock_held) 1179acbbeafSnn35248 mutex_enter(&pidlock); 1187c478bd9Sstevel@tonic-gate PID_RELE(sp->s_sidp); 1199acbbeafSnn35248 if (!pidlock_held) 1209acbbeafSnn35248 mutex_exit(&pidlock); 1219acbbeafSnn35248 1227c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_lock); 1239acbbeafSnn35248 cv_destroy(&sp->s_cnt_cv); 1247c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (sess_t)); 1257c478bd9Sstevel@tonic-gate } 1269acbbeafSnn35248 1279acbbeafSnn35248 sess_t * 1289acbbeafSnn35248 tty_hold(void) 1299acbbeafSnn35248 { 1309acbbeafSnn35248 proc_t *p = curproc; 1319acbbeafSnn35248 sess_t *sp; 1329acbbeafSnn35248 boolean_t got_sig = B_FALSE; 1339acbbeafSnn35248 1349acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 1359acbbeafSnn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 1369acbbeafSnn35248 1379acbbeafSnn35248 for (;;) { 1389acbbeafSnn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 1399acbbeafSnn35248 sp = p->p_sessp; 1409acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 1419acbbeafSnn35248 1429acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 1439acbbeafSnn35248 ASSERT((sp->s_vp == NULL) || 1449acbbeafSnn35248 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock)); 1459acbbeafSnn35248 1469acbbeafSnn35248 /* 1479acbbeafSnn35248 * If the session leader process is not exiting (and hence 1489acbbeafSnn35248 * not trying to release the session's ctty) then we can 1499acbbeafSnn35248 * safely grab a hold on the current session structure 1509acbbeafSnn35248 * and return it. If on the other hand the session leader 1519acbbeafSnn35248 * process is exiting and clearing the ctty then we'll 1529acbbeafSnn35248 * wait till it's done before we loop around and grab a 1539acbbeafSnn35248 * hold on the session structure. 1549acbbeafSnn35248 */ 1559acbbeafSnn35248 if (!sp->s_exit) 1569acbbeafSnn35248 break; 1579acbbeafSnn35248 1589acbbeafSnn35248 /* need to hold the session so it can't be freed */ 1599acbbeafSnn35248 sp->s_ref++; 1609acbbeafSnn35248 mutex_exit(&p->p_splock); 1619acbbeafSnn35248 1629acbbeafSnn35248 /* Wait till the session leader is done */ 1639acbbeafSnn35248 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock)) 1649acbbeafSnn35248 got_sig = B_TRUE; 1659acbbeafSnn35248 1669acbbeafSnn35248 /* 1679acbbeafSnn35248 * Now we need to drop our hold on the session structure, 1689acbbeafSnn35248 * but we can't hold any locks when we do this because 169*da6c28aaSamw * sess_rele() may need to acquire pidlock. 1709acbbeafSnn35248 */ 1719acbbeafSnn35248 mutex_exit(&sp->s_lock); 1729acbbeafSnn35248 sess_rele(sp, B_FALSE); 1739acbbeafSnn35248 1749acbbeafSnn35248 if (got_sig) 1759acbbeafSnn35248 return (NULL); 1769acbbeafSnn35248 } 1779acbbeafSnn35248 1789acbbeafSnn35248 /* whew, we finally got a hold */ 1799acbbeafSnn35248 sp->s_cnt++; 1809acbbeafSnn35248 sp->s_ref++; 1819acbbeafSnn35248 mutex_exit(&sp->s_lock); 1829acbbeafSnn35248 mutex_exit(&p->p_splock); 1839acbbeafSnn35248 return (sp); 1849acbbeafSnn35248 } 1859acbbeafSnn35248 1869acbbeafSnn35248 void 1879acbbeafSnn35248 tty_rele(sess_t *sp) 1889acbbeafSnn35248 { 1899acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 1909acbbeafSnn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 1919acbbeafSnn35248 1929acbbeafSnn35248 mutex_enter(&sp->s_lock); 1939acbbeafSnn35248 if ((--sp->s_cnt) == 0) 1949acbbeafSnn35248 cv_broadcast(&sp->s_cnt_cv); 1959acbbeafSnn35248 mutex_exit(&sp->s_lock); 1969acbbeafSnn35248 1979acbbeafSnn35248 sess_rele(sp, B_FALSE); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate void 2017c478bd9Sstevel@tonic-gate sess_create(void) 2027c478bd9Sstevel@tonic-gate { 2039acbbeafSnn35248 proc_t *p = curproc; 2049acbbeafSnn35248 sess_t *sp, *old_sp; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL); 2099acbbeafSnn35248 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2129acbbeafSnn35248 * we need to grap p_lock to protect p_pgidp because 2139acbbeafSnn35248 * /proc looks at p_pgidp while holding only p_lock. 2149acbbeafSnn35248 * 2159acbbeafSnn35248 * we don't need to hold p->p_sessp->s_lock or get a hold on the 2169acbbeafSnn35248 * session structure since we're not actually updating any of 2179acbbeafSnn35248 * the contents of the old session structure. 2187c478bd9Sstevel@tonic-gate */ 2199acbbeafSnn35248 mutex_enter(&pidlock); 2209acbbeafSnn35248 mutex_enter(&p->p_lock); 2219acbbeafSnn35248 mutex_enter(&p->p_splock); 2227c478bd9Sstevel@tonic-gate 2239acbbeafSnn35248 pgexit(p); 2249acbbeafSnn35248 2259acbbeafSnn35248 sp->s_sidp = p->p_pidp; 2267c478bd9Sstevel@tonic-gate sp->s_ref = 1; 2277c478bd9Sstevel@tonic-gate sp->s_dev = NODEV; 2287c478bd9Sstevel@tonic-gate 2299acbbeafSnn35248 old_sp = p->p_sessp; 2309acbbeafSnn35248 p->p_sessp = sp; 2317c478bd9Sstevel@tonic-gate 2329acbbeafSnn35248 pgjoin(p, p->p_pidp); 2339acbbeafSnn35248 PID_HOLD(p->p_pidp); 2347c478bd9Sstevel@tonic-gate 2359acbbeafSnn35248 mutex_exit(&p->p_splock); 2369acbbeafSnn35248 mutex_exit(&p->p_lock); 2377c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 2389acbbeafSnn35248 2399acbbeafSnn35248 sess_rele(old_sp, B_FALSE); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2429acbbeafSnn35248 /* 2439acbbeafSnn35248 * Note that sess_ctty_clear() resets all the fields in the session 2449acbbeafSnn35248 * structure but doesn't release any holds or free any objects 2459acbbeafSnn35248 * that the session structure might currently point to. it is the 2469acbbeafSnn35248 * callers responsibility to do this. 2479acbbeafSnn35248 */ 2489acbbeafSnn35248 static void 2499acbbeafSnn35248 sess_ctty_clear(sess_t *sp, stdata_t *stp) 2507c478bd9Sstevel@tonic-gate { 2519acbbeafSnn35248 /* 2529acbbeafSnn35248 * Assert that we hold all the necessary locks. We also need 2539acbbeafSnn35248 * to be holding proc_t->p_splock for the process associated 2549acbbeafSnn35248 * with this session, but since we don't have a proc pointer 2559acbbeafSnn35248 * passed in we can't assert this here. 2569acbbeafSnn35248 */ 2579acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 2589acbbeafSnn35248 MUTEX_HELD(&sp->s_lock)); 2597c478bd9Sstevel@tonic-gate 2609acbbeafSnn35248 /* reset the session structure members to defaults */ 2619acbbeafSnn35248 sp->s_sighuped = B_FALSE; 2629acbbeafSnn35248 sp->s_dev = NODEV; 2637c478bd9Sstevel@tonic-gate sp->s_vp = NULL; 264ad1660d0Smeem sp->s_cred = NULL; 2657c478bd9Sstevel@tonic-gate 2669acbbeafSnn35248 /* reset the stream session and group pointers */ 2679acbbeafSnn35248 stp->sd_pgidp = NULL; 2689acbbeafSnn35248 stp->sd_sidp = NULL; 2699acbbeafSnn35248 } 2707c478bd9Sstevel@tonic-gate 2719acbbeafSnn35248 static void 2729acbbeafSnn35248 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp) 2739acbbeafSnn35248 { 2749acbbeafSnn35248 cred_t *crp; 2759acbbeafSnn35248 2769acbbeafSnn35248 /* Assert that we hold all the necessary locks. */ 2779acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 2789acbbeafSnn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 2799acbbeafSnn35248 2809acbbeafSnn35248 /* get holds on structures */ 2819acbbeafSnn35248 mutex_enter(&p->p_crlock); 2829acbbeafSnn35248 crhold(crp = p->p_cred); 2839acbbeafSnn35248 mutex_exit(&p->p_crlock); 2849acbbeafSnn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 2859acbbeafSnn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 2869acbbeafSnn35248 2879acbbeafSnn35248 /* update the session structure members */ 2889acbbeafSnn35248 sp->s_vp = makectty(stp->sd_vnode); 2899acbbeafSnn35248 sp->s_dev = sp->s_vp->v_rdev; 2909acbbeafSnn35248 sp->s_cred = crp; 2919acbbeafSnn35248 2929acbbeafSnn35248 /* update the stream emebers */ 2939acbbeafSnn35248 stp->sd_flag |= STRISTTY; /* just to be sure */ 2949acbbeafSnn35248 stp->sd_sidp = sp->s_sidp; 2959acbbeafSnn35248 stp->sd_pgidp = sp->s_sidp; 2969acbbeafSnn35248 } 2979acbbeafSnn35248 2989acbbeafSnn35248 int 2999acbbeafSnn35248 strctty(stdata_t *stp) 3009acbbeafSnn35248 { 3019acbbeafSnn35248 sess_t *sp; 3029acbbeafSnn35248 proc_t *p = curproc; 3039acbbeafSnn35248 boolean_t got_sig = B_FALSE; 3049acbbeafSnn35248 3059acbbeafSnn35248 /* 3069acbbeafSnn35248 * We are going to try to make stp the default ctty for the session 3079acbbeafSnn35248 * associated with curproc. Not only does this require holding a 3089acbbeafSnn35248 * bunch of locks but it also requires waiting for any outstanding 309*da6c28aaSamw * holds on the session structure (acquired via tty_hold()) to be 3109acbbeafSnn35248 * released. Hence, we have the following for(;;) loop that will 311*da6c28aaSamw * acquire our locks, do some sanity checks, and wait for the hold 3129acbbeafSnn35248 * count on the session structure to hit zero. If we get a signal 3139acbbeafSnn35248 * while waiting for outstanding holds to be released then we abort 3149acbbeafSnn35248 * the operation and return. 3159acbbeafSnn35248 */ 3169acbbeafSnn35248 for (;;) { 3179acbbeafSnn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 3189acbbeafSnn35248 mutex_enter(&pidlock); /* protects p_pidp */ 3199acbbeafSnn35248 mutex_enter(&p->p_splock); /* protects p_sessp */ 3209acbbeafSnn35248 sp = p->p_sessp; 3219acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 3229acbbeafSnn35248 3239acbbeafSnn35248 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) || 3249acbbeafSnn35248 (stp->sd_sidp != NULL) || /* stp already ctty? */ 3259acbbeafSnn35248 (p->p_pidp != sp->s_sidp) || /* we're not leader? */ 3269acbbeafSnn35248 (sp->s_vp != NULL)) { /* session has ctty? */ 3277c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3289acbbeafSnn35248 mutex_exit(&p->p_splock); 3299acbbeafSnn35248 mutex_exit(&pidlock); 3309acbbeafSnn35248 mutex_exit(&stp->sd_lock); 3319acbbeafSnn35248 return (ENOTTY); 3329acbbeafSnn35248 } 3339acbbeafSnn35248 3349acbbeafSnn35248 /* sanity check. we can't be exiting right now */ 3359acbbeafSnn35248 ASSERT(!sp->s_exit); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3389acbbeafSnn35248 * If no one else has a hold on this session structure 3399acbbeafSnn35248 * then we now have exclusive access to it, so break out 3409acbbeafSnn35248 * of this loop and update the session structure. 3417c478bd9Sstevel@tonic-gate */ 3429acbbeafSnn35248 if (sp->s_cnt == 0) 3439acbbeafSnn35248 break; 3447c478bd9Sstevel@tonic-gate 3459acbbeafSnn35248 /* need to hold the session so it can't be freed */ 3469acbbeafSnn35248 sp->s_ref++; 3479acbbeafSnn35248 3489acbbeafSnn35248 /* ain't locking order fun? */ 3499acbbeafSnn35248 mutex_exit(&p->p_splock); 3509acbbeafSnn35248 mutex_exit(&pidlock); 3519acbbeafSnn35248 mutex_exit(&stp->sd_lock); 3529acbbeafSnn35248 3539acbbeafSnn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) 3549acbbeafSnn35248 got_sig = B_TRUE; 3559acbbeafSnn35248 mutex_exit(&sp->s_lock); 3569acbbeafSnn35248 sess_rele(sp, B_FALSE); 3579acbbeafSnn35248 3589acbbeafSnn35248 if (got_sig) 3599acbbeafSnn35248 return (EINTR); 3609acbbeafSnn35248 } 3619acbbeafSnn35248 3629acbbeafSnn35248 /* set the session ctty bindings */ 3639acbbeafSnn35248 sess_ctty_set(p, sp, stp); 3649acbbeafSnn35248 3659acbbeafSnn35248 mutex_exit(&sp->s_lock); 3669acbbeafSnn35248 mutex_exit(&p->p_splock); 3679acbbeafSnn35248 mutex_exit(&pidlock); 3689acbbeafSnn35248 mutex_exit(&stp->sd_lock); 3699acbbeafSnn35248 return (0); 3709acbbeafSnn35248 } 3719acbbeafSnn35248 3729acbbeafSnn35248 /* 373*da6c28aaSamw * freectty_lock() attempts to acquire the army of locks required to free 3749acbbeafSnn35248 * the ctty associated with a given session leader process. If it returns 3759acbbeafSnn35248 * successfully the following locks will be held: 3769acbbeafSnn35248 * sd_lock, pidlock, p_splock, s_lock 3779acbbeafSnn35248 * 378*da6c28aaSamw * as a secondary bit of convenience, freectty_lock() will also return 3799acbbeafSnn35248 * pointers to the session, ctty, and ctty stream associated with the 3809acbbeafSnn35248 * specified session leader process. 3819acbbeafSnn35248 */ 3829acbbeafSnn35248 static boolean_t 3839acbbeafSnn35248 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp, 3849acbbeafSnn35248 boolean_t at_exit) 3859acbbeafSnn35248 { 3869acbbeafSnn35248 sess_t *sp; 3879acbbeafSnn35248 vnode_t *vp; 3889acbbeafSnn35248 stdata_t *stp; 3899acbbeafSnn35248 3909acbbeafSnn35248 mutex_enter(&pidlock); /* protect p_pidp */ 3919acbbeafSnn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 3929acbbeafSnn35248 sp = p->p_sessp; 3939acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 3949acbbeafSnn35248 3959acbbeafSnn35248 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */ 3969acbbeafSnn35248 (sp->s_vp == NULL)) { /* no ctty? */ 3979acbbeafSnn35248 mutex_exit(&sp->s_lock); 3989acbbeafSnn35248 mutex_exit(&p->p_splock); 3999acbbeafSnn35248 mutex_exit(&pidlock); 4009acbbeafSnn35248 return (B_FALSE); 4019acbbeafSnn35248 } 4029acbbeafSnn35248 4039acbbeafSnn35248 vp = sp->s_vp; 4049acbbeafSnn35248 stp = sp->s_vp->v_stream; 4059acbbeafSnn35248 4069acbbeafSnn35248 if (at_exit) { 4079acbbeafSnn35248 /* stop anyone else calling tty_hold() */ 4089acbbeafSnn35248 sp->s_exit = B_TRUE; 4099acbbeafSnn35248 } else { 4109acbbeafSnn35248 /* 4119acbbeafSnn35248 * due to locking order we have to grab stp->sd_lock before 4129acbbeafSnn35248 * grabbing all the other proc/session locks. but after we 4139acbbeafSnn35248 * drop all our current locks it's possible that someone 4149acbbeafSnn35248 * could come in and change our current session or close 4159acbbeafSnn35248 * the current ctty (vp) there by making sp or stp invalid. 4169acbbeafSnn35248 * (a VN_HOLD on vp won't protect stp because that only 4179acbbeafSnn35248 * prevents the vnode from being freed not closed.) so 4189acbbeafSnn35248 * to prevent this we bump s_ref and s_cnt here. 4199acbbeafSnn35248 * 4209acbbeafSnn35248 * course this doesn't matter if we're the last thread in 4219acbbeafSnn35248 * an exiting process that is the session leader, since no 4229acbbeafSnn35248 * one else can change our session or free our ctty. 4239acbbeafSnn35248 */ 4249acbbeafSnn35248 sp->s_ref++; /* hold the session structure */ 4259acbbeafSnn35248 sp->s_cnt++; /* protect vp and stp */ 4269acbbeafSnn35248 } 4279acbbeafSnn35248 4289acbbeafSnn35248 /* drop our session locks */ 4299acbbeafSnn35248 mutex_exit(&sp->s_lock); 4309acbbeafSnn35248 mutex_exit(&p->p_splock); 4319acbbeafSnn35248 mutex_exit(&pidlock); 4329acbbeafSnn35248 4339acbbeafSnn35248 /* grab locks in the right order */ 4349acbbeafSnn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 4359acbbeafSnn35248 mutex_enter(&pidlock); /* protect p_pidp */ 4369acbbeafSnn35248 mutex_enter(&p->p_splock); /* protects p->p_sessp */ 4379acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 4389acbbeafSnn35248 4399acbbeafSnn35248 /* if the session has changed, abort mission */ 4409acbbeafSnn35248 if (sp != p->p_sessp) { 4419acbbeafSnn35248 /* 4429acbbeafSnn35248 * this can't happen during process exit since we're the 4439acbbeafSnn35248 * only thread in the process and we sure didn't change 4449acbbeafSnn35248 * our own session at this point. 4459acbbeafSnn35248 */ 4469acbbeafSnn35248 ASSERT(!at_exit); 4479acbbeafSnn35248 4489acbbeafSnn35248 /* release our locks and holds */ 4499acbbeafSnn35248 mutex_exit(&sp->s_lock); 4509acbbeafSnn35248 mutex_exit(&p->p_splock); 4519acbbeafSnn35248 mutex_exit(&pidlock); 4529acbbeafSnn35248 mutex_exit(&stp->sd_lock); 4539acbbeafSnn35248 tty_rele(sp); 4549acbbeafSnn35248 return (B_FALSE); 4559acbbeafSnn35248 } 4569acbbeafSnn35248 4579acbbeafSnn35248 /* 4589acbbeafSnn35248 * sanity checks. none of this should have changed since we had 4599acbbeafSnn35248 * holds on the current ctty. 4609acbbeafSnn35248 */ 4619acbbeafSnn35248 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */ 4629acbbeafSnn35248 ASSERT(sp->s_vp != NULL); /* a ctty exists */ 4639acbbeafSnn35248 ASSERT(vp == sp->s_vp); 4649acbbeafSnn35248 ASSERT(stp == sp->s_vp->v_stream); 4659acbbeafSnn35248 4669acbbeafSnn35248 /* release our holds */ 4679acbbeafSnn35248 if (!at_exit) { 4689acbbeafSnn35248 if ((--(sp)->s_cnt) == 0) 4699acbbeafSnn35248 cv_broadcast(&sp->s_cnt_cv); 4709acbbeafSnn35248 sp->s_ref--; 4719acbbeafSnn35248 ASSERT(sp->s_ref > 0); 4729acbbeafSnn35248 } 4739acbbeafSnn35248 4749acbbeafSnn35248 /* return our pointers */ 4759acbbeafSnn35248 *spp = sp; 4769acbbeafSnn35248 *vpp = vp; 4779acbbeafSnn35248 *stpp = stp; 4789acbbeafSnn35248 4799acbbeafSnn35248 return (B_TRUE); 4809acbbeafSnn35248 } 4819acbbeafSnn35248 4829acbbeafSnn35248 /* 4839acbbeafSnn35248 * Returns B_FALSE if no signal is sent to the process group associated with 4849acbbeafSnn35248 * this ctty. Returns B_TRUE if a signal is sent to the process group. 4859acbbeafSnn35248 * If it return B_TRUE it also means that all the locks we were holding 4869acbbeafSnn35248 * were dropped so that we could send the signal. 4879acbbeafSnn35248 */ 4889acbbeafSnn35248 static boolean_t 4899acbbeafSnn35248 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit) 4909acbbeafSnn35248 { 4919acbbeafSnn35248 /* Assert that we hold all the necessary locks. */ 4929acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 4939acbbeafSnn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 4949acbbeafSnn35248 4959acbbeafSnn35248 /* check if we already signaled this group */ 4969acbbeafSnn35248 if (sp->s_sighuped) 4979acbbeafSnn35248 return (B_FALSE); 4989acbbeafSnn35248 4999acbbeafSnn35248 sp->s_sighuped = B_TRUE; 5009acbbeafSnn35248 5019acbbeafSnn35248 if (!at_exit) { 5029acbbeafSnn35248 /* 5039acbbeafSnn35248 * once again, we're about to drop our army of locks and we 5049acbbeafSnn35248 * don't want sp or stp to be freed. (see the comment in 5059acbbeafSnn35248 * freectty_lock()) 5069acbbeafSnn35248 */ 5079acbbeafSnn35248 sp->s_ref++; /* hold the session structure */ 5089acbbeafSnn35248 sp->s_cnt++; /* protect vp and stp */ 5099acbbeafSnn35248 } 5109acbbeafSnn35248 5119acbbeafSnn35248 /* can't hold these locks while calling pgsignal() */ 5129acbbeafSnn35248 mutex_exit(&sp->s_lock); 5139acbbeafSnn35248 mutex_exit(&p->p_splock); 5149acbbeafSnn35248 mutex_exit(&pidlock); 5159acbbeafSnn35248 5169acbbeafSnn35248 /* signal anyone in the foreground process group */ 5179acbbeafSnn35248 pgsignal(stp->sd_pgidp, SIGHUP); 5189acbbeafSnn35248 5199acbbeafSnn35248 /* signal anyone blocked in poll on this stream */ 5209acbbeafSnn35248 if (!(stp->sd_flag & STRHUP)) 5219acbbeafSnn35248 strhup(stp); 5229acbbeafSnn35248 5239acbbeafSnn35248 mutex_exit(&stp->sd_lock); 5249acbbeafSnn35248 5259acbbeafSnn35248 /* release our holds */ 5269acbbeafSnn35248 if (!at_exit) 5279acbbeafSnn35248 tty_rele(sp); 5289acbbeafSnn35248 5299acbbeafSnn35248 return (B_TRUE); 5309acbbeafSnn35248 } 5319acbbeafSnn35248 5329acbbeafSnn35248 int 5339acbbeafSnn35248 freectty(boolean_t at_exit) 5349acbbeafSnn35248 { 5359acbbeafSnn35248 proc_t *p = curproc; 5369acbbeafSnn35248 stdata_t *stp; 5379acbbeafSnn35248 vnode_t *vp; 5389acbbeafSnn35248 cred_t *cred; 5399acbbeafSnn35248 sess_t *sp; 5409acbbeafSnn35248 struct pid *pgidp, *sidp; 5419acbbeafSnn35248 boolean_t got_sig = B_FALSE; 5429acbbeafSnn35248 5439acbbeafSnn35248 /* 5449acbbeafSnn35248 * If the current process is a session leader we are going to 5459acbbeafSnn35248 * try to release the ctty associated our current session. To 546*da6c28aaSamw * do this we need to acquire a bunch of locks, signal any 5479acbbeafSnn35248 * processes in the forground that are associated with the ctty, 5489acbbeafSnn35248 * and make sure no one has any outstanding holds on the current 549*da6c28aaSamw * session * structure (acquired via tty_hold()). Hence, we have 5509acbbeafSnn35248 * the following for(;;) loop that will do all this work for 5519acbbeafSnn35248 * us and break out when the hold count on the session structure 5529acbbeafSnn35248 * hits zero. 5539acbbeafSnn35248 */ 5549acbbeafSnn35248 for (;;) { 5559acbbeafSnn35248 if (!freectty_lock(p, &sp, &vp, &stp, at_exit)) 5569acbbeafSnn35248 return (EIO); 5579acbbeafSnn35248 5589acbbeafSnn35248 if (freectty_signal(p, sp, stp, at_exit)) { 559*da6c28aaSamw /* loop around to re-acquire locks */ 5609acbbeafSnn35248 continue; 5619acbbeafSnn35248 } 5629acbbeafSnn35248 5639acbbeafSnn35248 /* 5649acbbeafSnn35248 * Only a session leader process can free a ctty. So if 5659acbbeafSnn35248 * we've made it here we know we're a session leader and 5669acbbeafSnn35248 * if we're not actively exiting it impossible for another 5679acbbeafSnn35248 * thread in this process to be exiting. (Because that 5689acbbeafSnn35248 * thread would have already stopped all other threads 5699acbbeafSnn35248 * in the current process.) 5709acbbeafSnn35248 */ 5719acbbeafSnn35248 ASSERT(at_exit || !sp->s_exit); 5729acbbeafSnn35248 5739acbbeafSnn35248 /* 5749acbbeafSnn35248 * If no one else has a hold on this session structure 5759acbbeafSnn35248 * then we now have exclusive access to it, so break out 5769acbbeafSnn35248 * of this loop and update the session structure. 5779acbbeafSnn35248 */ 5789acbbeafSnn35248 if (sp->s_cnt == 0) 5799acbbeafSnn35248 break; 5809acbbeafSnn35248 5819acbbeafSnn35248 if (!at_exit) { 5829acbbeafSnn35248 /* need to hold the session so it can't be freed */ 5839acbbeafSnn35248 sp->s_ref++; 5849acbbeafSnn35248 } 5859acbbeafSnn35248 5869acbbeafSnn35248 /* ain't locking order fun? */ 5879acbbeafSnn35248 mutex_exit(&p->p_splock); 5889acbbeafSnn35248 mutex_exit(&pidlock); 5899acbbeafSnn35248 mutex_exit(&stp->sd_lock); 5909acbbeafSnn35248 5919acbbeafSnn35248 if (at_exit) { 5929acbbeafSnn35248 /* 5939acbbeafSnn35248 * if we're exiting then we can't allow this operation 5949acbbeafSnn35248 * to fail so we do a cw_wait() instead of a 5959acbbeafSnn35248 * cv_wait_sig(). if there are threads with active 5969acbbeafSnn35248 * holds on this ctty that are blocked, then 5979acbbeafSnn35248 * they should only be blocked in a cv_wait_sig() 5989acbbeafSnn35248 * and hopefully they were in the foreground process 5999acbbeafSnn35248 * group and recieved the SIGHUP we sent above. of 6009acbbeafSnn35248 * course it's possible that they weren't in the 6019acbbeafSnn35248 * foreground process group and didn't get our 6029acbbeafSnn35248 * signal (or they could be stopped by job control 6039acbbeafSnn35248 * in which case our signal wouldn't matter until 6049acbbeafSnn35248 * they are restarted). in this case we won't 6059acbbeafSnn35248 * exit until someone else sends them a signal. 6069acbbeafSnn35248 */ 6079acbbeafSnn35248 cv_wait(&sp->s_cnt_cv, &sp->s_lock); 6089acbbeafSnn35248 mutex_exit(&sp->s_lock); 6099acbbeafSnn35248 continue; 6109acbbeafSnn35248 } 6119acbbeafSnn35248 6129acbbeafSnn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) { 6139acbbeafSnn35248 got_sig = B_TRUE; 6149acbbeafSnn35248 } 6159acbbeafSnn35248 6169acbbeafSnn35248 mutex_exit(&sp->s_lock); 6179acbbeafSnn35248 sess_rele(sp, B_FALSE); 6189acbbeafSnn35248 6199acbbeafSnn35248 if (got_sig) 6209acbbeafSnn35248 return (EINTR); 6219acbbeafSnn35248 } 6229acbbeafSnn35248 ASSERT(sp->s_cnt == 0); 6239acbbeafSnn35248 6249acbbeafSnn35248 /* save some pointers for later */ 6259acbbeafSnn35248 cred = sp->s_cred; 6269acbbeafSnn35248 pgidp = stp->sd_pgidp; 6279acbbeafSnn35248 sidp = stp->sd_sidp; 6289acbbeafSnn35248 6299acbbeafSnn35248 /* clear the session ctty bindings */ 6309acbbeafSnn35248 sess_ctty_clear(sp, stp); 6319acbbeafSnn35248 6329acbbeafSnn35248 /* wake up anyone blocked in tty_hold() */ 6339acbbeafSnn35248 if (at_exit) { 6349acbbeafSnn35248 ASSERT(sp->s_exit); 6359acbbeafSnn35248 sp->s_exit = B_FALSE; 6369acbbeafSnn35248 cv_broadcast(&sp->s_exit_cv); 6379acbbeafSnn35248 } 6389acbbeafSnn35248 6399acbbeafSnn35248 /* we can drop these locks now */ 6409acbbeafSnn35248 mutex_exit(&sp->s_lock); 6419acbbeafSnn35248 mutex_exit(&p->p_splock); 6429acbbeafSnn35248 mutex_exit(&pidlock); 6439acbbeafSnn35248 mutex_exit(&stp->sd_lock); 6449acbbeafSnn35248 6459acbbeafSnn35248 /* This is the only remaining thread with access to this vnode */ 646*da6c28aaSamw (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL); 6477c478bd9Sstevel@tonic-gate VN_RELE(vp); 6487c478bd9Sstevel@tonic-gate crfree(cred); 6499acbbeafSnn35248 6509acbbeafSnn35248 /* release our holds on assorted structures and return */ 6519acbbeafSnn35248 mutex_enter(&pidlock); 6529acbbeafSnn35248 PID_RELE(pgidp); 6539acbbeafSnn35248 PID_RELE(sidp); 6549acbbeafSnn35248 mutex_exit(&pidlock); 6559acbbeafSnn35248 6569acbbeafSnn35248 return (1); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * ++++++++++++++++++++++++ 6617c478bd9Sstevel@tonic-gate * ++ SunOS4.1 Buyback ++ 6627c478bd9Sstevel@tonic-gate * ++++++++++++++++++++++++ 6637c478bd9Sstevel@tonic-gate * 6647c478bd9Sstevel@tonic-gate * vhangup: Revoke access of the current tty by all processes 6657c478bd9Sstevel@tonic-gate * Used by privileged users to give a "clean" terminal at login 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate int 668ad1660d0Smeem vhangup(void) 6697c478bd9Sstevel@tonic-gate { 6707c478bd9Sstevel@tonic-gate if (secpolicy_sys_config(CRED(), B_FALSE) != 0) 6717c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * This routine used to call freectty() under a condition that 6747c478bd9Sstevel@tonic-gate * could never happen. So this code has never actually done 675ad1660d0Smeem * anything, and evidently nobody has ever noticed. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate return (0); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate dev_t 6817c478bd9Sstevel@tonic-gate cttydev(proc_t *pp) 6827c478bd9Sstevel@tonic-gate { 6839acbbeafSnn35248 sess_t *sp; 6849acbbeafSnn35248 dev_t dev; 6859acbbeafSnn35248 6869acbbeafSnn35248 mutex_enter(&pp->p_splock); /* protects p->p_sessp */ 6879acbbeafSnn35248 sp = pp->p_sessp; 6889acbbeafSnn35248 6899acbbeafSnn35248 #ifdef DEBUG 6909acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 6917c478bd9Sstevel@tonic-gate if (sp->s_vp == NULL) 6929acbbeafSnn35248 ASSERT(sp->s_dev == NODEV); 6939acbbeafSnn35248 else 6949acbbeafSnn35248 ASSERT(sp->s_dev != NODEV); 6959acbbeafSnn35248 mutex_exit(&sp->s_lock); 6969acbbeafSnn35248 #endif /* DEBUG */ 6979acbbeafSnn35248 6989acbbeafSnn35248 dev = sp->s_dev; 6999acbbeafSnn35248 mutex_exit(&pp->p_splock); 7009acbbeafSnn35248 return (dev); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate void 7049acbbeafSnn35248 ctty_clear_sighuped(void) 7057c478bd9Sstevel@tonic-gate { 7069acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock)); 7079acbbeafSnn35248 curproc->p_sessp->s_sighuped = B_FALSE; 7087c478bd9Sstevel@tonic-gate } 709