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 5*9acbbeafSnn35248 * Common Development and Distribution License (the "License"). 6*9acbbeafSnn35248 * 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*9acbbeafSnn35248 * Copyright 2006 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> 49*9acbbeafSnn35248 #include <sys/fs/snode.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate sess_t session0 = { 52*9acbbeafSnn35248 &pid0, /* s_sidp */ 53*9acbbeafSnn35248 {0}, /* s_lock */ 547c478bd9Sstevel@tonic-gate 1, /* s_ref */ 55*9acbbeafSnn35248 B_FALSE, /* s_sighuped */ 56*9acbbeafSnn35248 B_FALSE, /* s_exit */ 57*9acbbeafSnn35248 0, /* s_exit_cv */ 58*9acbbeafSnn35248 0, /* s_cnt */ 59*9acbbeafSnn35248 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 66*9acbbeafSnn35248 sess_hold(proc_t *p) 677c478bd9Sstevel@tonic-gate { 68*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock)); 69*9acbbeafSnn35248 mutex_enter(&p->p_sessp->s_lock); 70*9acbbeafSnn35248 p->p_sessp->s_ref++; 71*9acbbeafSnn35248 mutex_exit(&p->p_sessp->s_lock); 72*9acbbeafSnn35248 } 73*9acbbeafSnn35248 74*9acbbeafSnn35248 void 75*9acbbeafSnn35248 sess_rele(sess_t *sp, boolean_t pidlock_held) 76*9acbbeafSnn35248 { 77*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held); 78*9acbbeafSnn35248 79*9acbbeafSnn35248 mutex_enter(&sp->s_lock); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate ASSERT(sp->s_ref != 0); 82*9acbbeafSnn35248 if (--sp->s_ref > 0) { 83*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 84*9acbbeafSnn35248 return; 85*9acbbeafSnn35248 } 86*9acbbeafSnn35248 ASSERT(sp->s_ref == 0); 87*9acbbeafSnn35248 88*9acbbeafSnn35248 /* 89*9acbbeafSnn35248 * It's ok to free this session structure now because we know 90*9acbbeafSnn35248 * that no one else can have a pointer to it. We know this 91*9acbbeafSnn35248 * to be true because the only time that s_ref can possibly 92*9acbbeafSnn35248 * be incremented is when pidlock or p_splock is held AND there 93*9acbbeafSnn35248 * is a proc_t that points to that session structure. In that 94*9acbbeafSnn35248 * case we are guaranteed that the s_ref is at least 1 since there 95*9acbbeafSnn35248 * is a proc_t that points to it. So when s_ref finally drops to 96*9acbbeafSnn35248 * zero then no one else has a reference (and hence pointer) to 97*9acbbeafSnn35248 * this session structure and there is no valid proc_t pointing 98*9acbbeafSnn35248 * to this session structure anymore so, no one can acquire a 99*9acbbeafSnn35248 * reference (and pointer) to this session structure so it's 100*9acbbeafSnn35248 * ok to free it here. 101*9acbbeafSnn35248 */ 102*9acbbeafSnn35248 1037c478bd9Sstevel@tonic-gate if (sp == &session0) 1047c478bd9Sstevel@tonic-gate panic("sp == &session0"); 105*9acbbeafSnn35248 106*9acbbeafSnn35248 /* make sure there are no outstanding holds */ 107*9acbbeafSnn35248 ASSERT(sp->s_cnt == 0); 108*9acbbeafSnn35248 109*9acbbeafSnn35248 /* make sure there is no exit in progress */ 110*9acbbeafSnn35248 ASSERT(!sp->s_exit); 111*9acbbeafSnn35248 112*9acbbeafSnn35248 /* make sure someone already freed any ctty */ 113*9acbbeafSnn35248 ASSERT(sp->s_vp == NULL); 114*9acbbeafSnn35248 ASSERT(sp->s_dev == NODEV); 115*9acbbeafSnn35248 116*9acbbeafSnn35248 if (!pidlock_held) 117*9acbbeafSnn35248 mutex_enter(&pidlock); 1187c478bd9Sstevel@tonic-gate PID_RELE(sp->s_sidp); 119*9acbbeafSnn35248 if (!pidlock_held) 120*9acbbeafSnn35248 mutex_exit(&pidlock); 121*9acbbeafSnn35248 1227c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_lock); 123*9acbbeafSnn35248 cv_destroy(&sp->s_cnt_cv); 1247c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (sess_t)); 1257c478bd9Sstevel@tonic-gate } 126*9acbbeafSnn35248 127*9acbbeafSnn35248 sess_t * 128*9acbbeafSnn35248 tty_hold(void) 129*9acbbeafSnn35248 { 130*9acbbeafSnn35248 proc_t *p = curproc; 131*9acbbeafSnn35248 sess_t *sp; 132*9acbbeafSnn35248 boolean_t got_sig = B_FALSE; 133*9acbbeafSnn35248 134*9acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 135*9acbbeafSnn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 136*9acbbeafSnn35248 137*9acbbeafSnn35248 for (;;) { 138*9acbbeafSnn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 139*9acbbeafSnn35248 sp = p->p_sessp; 140*9acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 141*9acbbeafSnn35248 142*9acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 143*9acbbeafSnn35248 ASSERT((sp->s_vp == NULL) || 144*9acbbeafSnn35248 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock)); 145*9acbbeafSnn35248 146*9acbbeafSnn35248 /* 147*9acbbeafSnn35248 * If the session leader process is not exiting (and hence 148*9acbbeafSnn35248 * not trying to release the session's ctty) then we can 149*9acbbeafSnn35248 * safely grab a hold on the current session structure 150*9acbbeafSnn35248 * and return it. If on the other hand the session leader 151*9acbbeafSnn35248 * process is exiting and clearing the ctty then we'll 152*9acbbeafSnn35248 * wait till it's done before we loop around and grab a 153*9acbbeafSnn35248 * hold on the session structure. 154*9acbbeafSnn35248 */ 155*9acbbeafSnn35248 if (!sp->s_exit) 156*9acbbeafSnn35248 break; 157*9acbbeafSnn35248 158*9acbbeafSnn35248 /* need to hold the session so it can't be freed */ 159*9acbbeafSnn35248 sp->s_ref++; 160*9acbbeafSnn35248 mutex_exit(&p->p_splock); 161*9acbbeafSnn35248 162*9acbbeafSnn35248 /* Wait till the session leader is done */ 163*9acbbeafSnn35248 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock)) 164*9acbbeafSnn35248 got_sig = B_TRUE; 165*9acbbeafSnn35248 166*9acbbeafSnn35248 /* 167*9acbbeafSnn35248 * Now we need to drop our hold on the session structure, 168*9acbbeafSnn35248 * but we can't hold any locks when we do this because 169*9acbbeafSnn35248 * sess_rele() may need to aquire pidlock. 170*9acbbeafSnn35248 */ 171*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 172*9acbbeafSnn35248 sess_rele(sp, B_FALSE); 173*9acbbeafSnn35248 174*9acbbeafSnn35248 if (got_sig) 175*9acbbeafSnn35248 return (NULL); 176*9acbbeafSnn35248 } 177*9acbbeafSnn35248 178*9acbbeafSnn35248 /* whew, we finally got a hold */ 179*9acbbeafSnn35248 sp->s_cnt++; 180*9acbbeafSnn35248 sp->s_ref++; 181*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 182*9acbbeafSnn35248 mutex_exit(&p->p_splock); 183*9acbbeafSnn35248 return (sp); 184*9acbbeafSnn35248 } 185*9acbbeafSnn35248 186*9acbbeafSnn35248 void 187*9acbbeafSnn35248 tty_rele(sess_t *sp) 188*9acbbeafSnn35248 { 189*9acbbeafSnn35248 /* make sure the caller isn't holding locks they shouldn't */ 190*9acbbeafSnn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 191*9acbbeafSnn35248 192*9acbbeafSnn35248 mutex_enter(&sp->s_lock); 193*9acbbeafSnn35248 if ((--sp->s_cnt) == 0) 194*9acbbeafSnn35248 cv_broadcast(&sp->s_cnt_cv); 195*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 196*9acbbeafSnn35248 197*9acbbeafSnn35248 sess_rele(sp, B_FALSE); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate void 2017c478bd9Sstevel@tonic-gate sess_create(void) 2027c478bd9Sstevel@tonic-gate { 203*9acbbeafSnn35248 proc_t *p = curproc; 204*9acbbeafSnn35248 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); 209*9acbbeafSnn35248 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 212*9acbbeafSnn35248 * we need to grap p_lock to protect p_pgidp because 213*9acbbeafSnn35248 * /proc looks at p_pgidp while holding only p_lock. 214*9acbbeafSnn35248 * 215*9acbbeafSnn35248 * we don't need to hold p->p_sessp->s_lock or get a hold on the 216*9acbbeafSnn35248 * session structure since we're not actually updating any of 217*9acbbeafSnn35248 * the contents of the old session structure. 2187c478bd9Sstevel@tonic-gate */ 219*9acbbeafSnn35248 mutex_enter(&pidlock); 220*9acbbeafSnn35248 mutex_enter(&p->p_lock); 221*9acbbeafSnn35248 mutex_enter(&p->p_splock); 2227c478bd9Sstevel@tonic-gate 223*9acbbeafSnn35248 pgexit(p); 224*9acbbeafSnn35248 225*9acbbeafSnn35248 sp->s_sidp = p->p_pidp; 2267c478bd9Sstevel@tonic-gate sp->s_ref = 1; 2277c478bd9Sstevel@tonic-gate sp->s_dev = NODEV; 2287c478bd9Sstevel@tonic-gate 229*9acbbeafSnn35248 old_sp = p->p_sessp; 230*9acbbeafSnn35248 p->p_sessp = sp; 2317c478bd9Sstevel@tonic-gate 232*9acbbeafSnn35248 pgjoin(p, p->p_pidp); 233*9acbbeafSnn35248 PID_HOLD(p->p_pidp); 2347c478bd9Sstevel@tonic-gate 235*9acbbeafSnn35248 mutex_exit(&p->p_splock); 236*9acbbeafSnn35248 mutex_exit(&p->p_lock); 2377c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 238*9acbbeafSnn35248 239*9acbbeafSnn35248 sess_rele(old_sp, B_FALSE); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 242*9acbbeafSnn35248 /* 243*9acbbeafSnn35248 * Note that sess_ctty_clear() resets all the fields in the session 244*9acbbeafSnn35248 * structure but doesn't release any holds or free any objects 245*9acbbeafSnn35248 * that the session structure might currently point to. it is the 246*9acbbeafSnn35248 * callers responsibility to do this. 247*9acbbeafSnn35248 */ 248*9acbbeafSnn35248 static void 249*9acbbeafSnn35248 sess_ctty_clear(sess_t *sp, stdata_t *stp) 2507c478bd9Sstevel@tonic-gate { 251*9acbbeafSnn35248 /* 252*9acbbeafSnn35248 * Assert that we hold all the necessary locks. We also need 253*9acbbeafSnn35248 * to be holding proc_t->p_splock for the process associated 254*9acbbeafSnn35248 * with this session, but since we don't have a proc pointer 255*9acbbeafSnn35248 * passed in we can't assert this here. 256*9acbbeafSnn35248 */ 257*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 258*9acbbeafSnn35248 MUTEX_HELD(&sp->s_lock)); 2597c478bd9Sstevel@tonic-gate 260*9acbbeafSnn35248 /* reset the session structure members to defaults */ 261*9acbbeafSnn35248 sp->s_sighuped = B_FALSE; 262*9acbbeafSnn35248 sp->s_dev = NODEV; 2637c478bd9Sstevel@tonic-gate sp->s_vp = NULL; 264ad1660d0Smeem sp->s_cred = NULL; 2657c478bd9Sstevel@tonic-gate 266*9acbbeafSnn35248 /* reset the stream session and group pointers */ 267*9acbbeafSnn35248 stp->sd_pgidp = NULL; 268*9acbbeafSnn35248 stp->sd_sidp = NULL; 269*9acbbeafSnn35248 } 2707c478bd9Sstevel@tonic-gate 271*9acbbeafSnn35248 static void 272*9acbbeafSnn35248 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp) 273*9acbbeafSnn35248 { 274*9acbbeafSnn35248 cred_t *crp; 275*9acbbeafSnn35248 276*9acbbeafSnn35248 /* Assert that we hold all the necessary locks. */ 277*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 278*9acbbeafSnn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 279*9acbbeafSnn35248 280*9acbbeafSnn35248 /* get holds on structures */ 281*9acbbeafSnn35248 mutex_enter(&p->p_crlock); 282*9acbbeafSnn35248 crhold(crp = p->p_cred); 283*9acbbeafSnn35248 mutex_exit(&p->p_crlock); 284*9acbbeafSnn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 285*9acbbeafSnn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 286*9acbbeafSnn35248 287*9acbbeafSnn35248 /* update the session structure members */ 288*9acbbeafSnn35248 sp->s_vp = makectty(stp->sd_vnode); 289*9acbbeafSnn35248 sp->s_dev = sp->s_vp->v_rdev; 290*9acbbeafSnn35248 sp->s_cred = crp; 291*9acbbeafSnn35248 292*9acbbeafSnn35248 /* update the stream emebers */ 293*9acbbeafSnn35248 stp->sd_flag |= STRISTTY; /* just to be sure */ 294*9acbbeafSnn35248 stp->sd_sidp = sp->s_sidp; 295*9acbbeafSnn35248 stp->sd_pgidp = sp->s_sidp; 296*9acbbeafSnn35248 } 297*9acbbeafSnn35248 298*9acbbeafSnn35248 int 299*9acbbeafSnn35248 strctty(stdata_t *stp) 300*9acbbeafSnn35248 { 301*9acbbeafSnn35248 sess_t *sp; 302*9acbbeafSnn35248 proc_t *p = curproc; 303*9acbbeafSnn35248 boolean_t got_sig = B_FALSE; 304*9acbbeafSnn35248 305*9acbbeafSnn35248 /* 306*9acbbeafSnn35248 * We are going to try to make stp the default ctty for the session 307*9acbbeafSnn35248 * associated with curproc. Not only does this require holding a 308*9acbbeafSnn35248 * bunch of locks but it also requires waiting for any outstanding 309*9acbbeafSnn35248 * holds on the session structure (aquired via tty_hold()) to be 310*9acbbeafSnn35248 * released. Hence, we have the following for(;;) loop that will 311*9acbbeafSnn35248 * aquire our locks, do some sanity checks, and wait for the hold 312*9acbbeafSnn35248 * count on the session structure to hit zero. If we get a signal 313*9acbbeafSnn35248 * while waiting for outstanding holds to be released then we abort 314*9acbbeafSnn35248 * the operation and return. 315*9acbbeafSnn35248 */ 316*9acbbeafSnn35248 for (;;) { 317*9acbbeafSnn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 318*9acbbeafSnn35248 mutex_enter(&pidlock); /* protects p_pidp */ 319*9acbbeafSnn35248 mutex_enter(&p->p_splock); /* protects p_sessp */ 320*9acbbeafSnn35248 sp = p->p_sessp; 321*9acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 322*9acbbeafSnn35248 323*9acbbeafSnn35248 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) || 324*9acbbeafSnn35248 (stp->sd_sidp != NULL) || /* stp already ctty? */ 325*9acbbeafSnn35248 (p->p_pidp != sp->s_sidp) || /* we're not leader? */ 326*9acbbeafSnn35248 (sp->s_vp != NULL)) { /* session has ctty? */ 3277c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 328*9acbbeafSnn35248 mutex_exit(&p->p_splock); 329*9acbbeafSnn35248 mutex_exit(&pidlock); 330*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 331*9acbbeafSnn35248 return (ENOTTY); 332*9acbbeafSnn35248 } 333*9acbbeafSnn35248 334*9acbbeafSnn35248 /* sanity check. we can't be exiting right now */ 335*9acbbeafSnn35248 ASSERT(!sp->s_exit); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 338*9acbbeafSnn35248 * If no one else has a hold on this session structure 339*9acbbeafSnn35248 * then we now have exclusive access to it, so break out 340*9acbbeafSnn35248 * of this loop and update the session structure. 3417c478bd9Sstevel@tonic-gate */ 342*9acbbeafSnn35248 if (sp->s_cnt == 0) 343*9acbbeafSnn35248 break; 3447c478bd9Sstevel@tonic-gate 345*9acbbeafSnn35248 /* need to hold the session so it can't be freed */ 346*9acbbeafSnn35248 sp->s_ref++; 347*9acbbeafSnn35248 348*9acbbeafSnn35248 /* ain't locking order fun? */ 349*9acbbeafSnn35248 mutex_exit(&p->p_splock); 350*9acbbeafSnn35248 mutex_exit(&pidlock); 351*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 352*9acbbeafSnn35248 353*9acbbeafSnn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) 354*9acbbeafSnn35248 got_sig = B_TRUE; 355*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 356*9acbbeafSnn35248 sess_rele(sp, B_FALSE); 357*9acbbeafSnn35248 358*9acbbeafSnn35248 if (got_sig) 359*9acbbeafSnn35248 return (EINTR); 360*9acbbeafSnn35248 } 361*9acbbeafSnn35248 362*9acbbeafSnn35248 /* set the session ctty bindings */ 363*9acbbeafSnn35248 sess_ctty_set(p, sp, stp); 364*9acbbeafSnn35248 365*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 366*9acbbeafSnn35248 mutex_exit(&p->p_splock); 367*9acbbeafSnn35248 mutex_exit(&pidlock); 368*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 369*9acbbeafSnn35248 return (0); 370*9acbbeafSnn35248 } 371*9acbbeafSnn35248 372*9acbbeafSnn35248 /* 373*9acbbeafSnn35248 * freectty_lock() attempts to aquire the army of locks required to free 374*9acbbeafSnn35248 * the ctty associated with a given session leader process. If it returns 375*9acbbeafSnn35248 * successfully the following locks will be held: 376*9acbbeafSnn35248 * sd_lock, pidlock, p_splock, s_lock 377*9acbbeafSnn35248 * 378*9acbbeafSnn35248 * as a secondary bit of convience, freectty_lock() will also return 379*9acbbeafSnn35248 * pointers to the session, ctty, and ctty stream associated with the 380*9acbbeafSnn35248 * specified session leader process. 381*9acbbeafSnn35248 */ 382*9acbbeafSnn35248 static boolean_t 383*9acbbeafSnn35248 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp, 384*9acbbeafSnn35248 boolean_t at_exit) 385*9acbbeafSnn35248 { 386*9acbbeafSnn35248 sess_t *sp; 387*9acbbeafSnn35248 vnode_t *vp; 388*9acbbeafSnn35248 stdata_t *stp; 389*9acbbeafSnn35248 390*9acbbeafSnn35248 mutex_enter(&pidlock); /* protect p_pidp */ 391*9acbbeafSnn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 392*9acbbeafSnn35248 sp = p->p_sessp; 393*9acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 394*9acbbeafSnn35248 395*9acbbeafSnn35248 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */ 396*9acbbeafSnn35248 (sp->s_vp == NULL)) { /* no ctty? */ 397*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 398*9acbbeafSnn35248 mutex_exit(&p->p_splock); 399*9acbbeafSnn35248 mutex_exit(&pidlock); 400*9acbbeafSnn35248 return (B_FALSE); 401*9acbbeafSnn35248 } 402*9acbbeafSnn35248 403*9acbbeafSnn35248 vp = sp->s_vp; 404*9acbbeafSnn35248 stp = sp->s_vp->v_stream; 405*9acbbeafSnn35248 406*9acbbeafSnn35248 if (at_exit) { 407*9acbbeafSnn35248 /* stop anyone else calling tty_hold() */ 408*9acbbeafSnn35248 sp->s_exit = B_TRUE; 409*9acbbeafSnn35248 } else { 410*9acbbeafSnn35248 /* 411*9acbbeafSnn35248 * due to locking order we have to grab stp->sd_lock before 412*9acbbeafSnn35248 * grabbing all the other proc/session locks. but after we 413*9acbbeafSnn35248 * drop all our current locks it's possible that someone 414*9acbbeafSnn35248 * could come in and change our current session or close 415*9acbbeafSnn35248 * the current ctty (vp) there by making sp or stp invalid. 416*9acbbeafSnn35248 * (a VN_HOLD on vp won't protect stp because that only 417*9acbbeafSnn35248 * prevents the vnode from being freed not closed.) so 418*9acbbeafSnn35248 * to prevent this we bump s_ref and s_cnt here. 419*9acbbeafSnn35248 * 420*9acbbeafSnn35248 * course this doesn't matter if we're the last thread in 421*9acbbeafSnn35248 * an exiting process that is the session leader, since no 422*9acbbeafSnn35248 * one else can change our session or free our ctty. 423*9acbbeafSnn35248 */ 424*9acbbeafSnn35248 sp->s_ref++; /* hold the session structure */ 425*9acbbeafSnn35248 sp->s_cnt++; /* protect vp and stp */ 426*9acbbeafSnn35248 } 427*9acbbeafSnn35248 428*9acbbeafSnn35248 /* drop our session locks */ 429*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 430*9acbbeafSnn35248 mutex_exit(&p->p_splock); 431*9acbbeafSnn35248 mutex_exit(&pidlock); 432*9acbbeafSnn35248 433*9acbbeafSnn35248 /* grab locks in the right order */ 434*9acbbeafSnn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 435*9acbbeafSnn35248 mutex_enter(&pidlock); /* protect p_pidp */ 436*9acbbeafSnn35248 mutex_enter(&p->p_splock); /* protects p->p_sessp */ 437*9acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 438*9acbbeafSnn35248 439*9acbbeafSnn35248 /* if the session has changed, abort mission */ 440*9acbbeafSnn35248 if (sp != p->p_sessp) { 441*9acbbeafSnn35248 /* 442*9acbbeafSnn35248 * this can't happen during process exit since we're the 443*9acbbeafSnn35248 * only thread in the process and we sure didn't change 444*9acbbeafSnn35248 * our own session at this point. 445*9acbbeafSnn35248 */ 446*9acbbeafSnn35248 ASSERT(!at_exit); 447*9acbbeafSnn35248 448*9acbbeafSnn35248 /* release our locks and holds */ 449*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 450*9acbbeafSnn35248 mutex_exit(&p->p_splock); 451*9acbbeafSnn35248 mutex_exit(&pidlock); 452*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 453*9acbbeafSnn35248 tty_rele(sp); 454*9acbbeafSnn35248 return (B_FALSE); 455*9acbbeafSnn35248 } 456*9acbbeafSnn35248 457*9acbbeafSnn35248 /* 458*9acbbeafSnn35248 * sanity checks. none of this should have changed since we had 459*9acbbeafSnn35248 * holds on the current ctty. 460*9acbbeafSnn35248 */ 461*9acbbeafSnn35248 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */ 462*9acbbeafSnn35248 ASSERT(sp->s_vp != NULL); /* a ctty exists */ 463*9acbbeafSnn35248 ASSERT(vp == sp->s_vp); 464*9acbbeafSnn35248 ASSERT(stp == sp->s_vp->v_stream); 465*9acbbeafSnn35248 466*9acbbeafSnn35248 /* release our holds */ 467*9acbbeafSnn35248 if (!at_exit) { 468*9acbbeafSnn35248 if ((--(sp)->s_cnt) == 0) 469*9acbbeafSnn35248 cv_broadcast(&sp->s_cnt_cv); 470*9acbbeafSnn35248 sp->s_ref--; 471*9acbbeafSnn35248 ASSERT(sp->s_ref > 0); 472*9acbbeafSnn35248 } 473*9acbbeafSnn35248 474*9acbbeafSnn35248 /* return our pointers */ 475*9acbbeafSnn35248 *spp = sp; 476*9acbbeafSnn35248 *vpp = vp; 477*9acbbeafSnn35248 *stpp = stp; 478*9acbbeafSnn35248 479*9acbbeafSnn35248 return (B_TRUE); 480*9acbbeafSnn35248 } 481*9acbbeafSnn35248 482*9acbbeafSnn35248 /* 483*9acbbeafSnn35248 * Returns B_FALSE if no signal is sent to the process group associated with 484*9acbbeafSnn35248 * this ctty. Returns B_TRUE if a signal is sent to the process group. 485*9acbbeafSnn35248 * If it return B_TRUE it also means that all the locks we were holding 486*9acbbeafSnn35248 * were dropped so that we could send the signal. 487*9acbbeafSnn35248 */ 488*9acbbeafSnn35248 static boolean_t 489*9acbbeafSnn35248 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit) 490*9acbbeafSnn35248 { 491*9acbbeafSnn35248 /* Assert that we hold all the necessary locks. */ 492*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 493*9acbbeafSnn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 494*9acbbeafSnn35248 495*9acbbeafSnn35248 /* check if we already signaled this group */ 496*9acbbeafSnn35248 if (sp->s_sighuped) 497*9acbbeafSnn35248 return (B_FALSE); 498*9acbbeafSnn35248 499*9acbbeafSnn35248 sp->s_sighuped = B_TRUE; 500*9acbbeafSnn35248 501*9acbbeafSnn35248 if (!at_exit) { 502*9acbbeafSnn35248 /* 503*9acbbeafSnn35248 * once again, we're about to drop our army of locks and we 504*9acbbeafSnn35248 * don't want sp or stp to be freed. (see the comment in 505*9acbbeafSnn35248 * freectty_lock()) 506*9acbbeafSnn35248 */ 507*9acbbeafSnn35248 sp->s_ref++; /* hold the session structure */ 508*9acbbeafSnn35248 sp->s_cnt++; /* protect vp and stp */ 509*9acbbeafSnn35248 } 510*9acbbeafSnn35248 511*9acbbeafSnn35248 /* can't hold these locks while calling pgsignal() */ 512*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 513*9acbbeafSnn35248 mutex_exit(&p->p_splock); 514*9acbbeafSnn35248 mutex_exit(&pidlock); 515*9acbbeafSnn35248 516*9acbbeafSnn35248 /* signal anyone in the foreground process group */ 517*9acbbeafSnn35248 pgsignal(stp->sd_pgidp, SIGHUP); 518*9acbbeafSnn35248 519*9acbbeafSnn35248 /* signal anyone blocked in poll on this stream */ 520*9acbbeafSnn35248 if (!(stp->sd_flag & STRHUP)) 521*9acbbeafSnn35248 strhup(stp); 522*9acbbeafSnn35248 523*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 524*9acbbeafSnn35248 525*9acbbeafSnn35248 /* release our holds */ 526*9acbbeafSnn35248 if (!at_exit) 527*9acbbeafSnn35248 tty_rele(sp); 528*9acbbeafSnn35248 529*9acbbeafSnn35248 return (B_TRUE); 530*9acbbeafSnn35248 } 531*9acbbeafSnn35248 532*9acbbeafSnn35248 int 533*9acbbeafSnn35248 freectty(boolean_t at_exit) 534*9acbbeafSnn35248 { 535*9acbbeafSnn35248 proc_t *p = curproc; 536*9acbbeafSnn35248 stdata_t *stp; 537*9acbbeafSnn35248 vnode_t *vp; 538*9acbbeafSnn35248 cred_t *cred; 539*9acbbeafSnn35248 sess_t *sp; 540*9acbbeafSnn35248 struct pid *pgidp, *sidp; 541*9acbbeafSnn35248 boolean_t got_sig = B_FALSE; 542*9acbbeafSnn35248 543*9acbbeafSnn35248 /* 544*9acbbeafSnn35248 * If the current process is a session leader we are going to 545*9acbbeafSnn35248 * try to release the ctty associated our current session. To 546*9acbbeafSnn35248 * do this we need to aquire a bunch of locks, signal any 547*9acbbeafSnn35248 * processes in the forground that are associated with the ctty, 548*9acbbeafSnn35248 * and make sure no one has any outstanding holds on the current 549*9acbbeafSnn35248 * session * structure (aquired via tty_hold()). Hence, we have 550*9acbbeafSnn35248 * the following for(;;) loop that will do all this work for 551*9acbbeafSnn35248 * us and break out when the hold count on the session structure 552*9acbbeafSnn35248 * hits zero. 553*9acbbeafSnn35248 */ 554*9acbbeafSnn35248 for (;;) { 555*9acbbeafSnn35248 if (!freectty_lock(p, &sp, &vp, &stp, at_exit)) 556*9acbbeafSnn35248 return (EIO); 557*9acbbeafSnn35248 558*9acbbeafSnn35248 if (freectty_signal(p, sp, stp, at_exit)) { 559*9acbbeafSnn35248 /* loop around to re-aquire locks */ 560*9acbbeafSnn35248 continue; 561*9acbbeafSnn35248 } 562*9acbbeafSnn35248 563*9acbbeafSnn35248 /* 564*9acbbeafSnn35248 * Only a session leader process can free a ctty. So if 565*9acbbeafSnn35248 * we've made it here we know we're a session leader and 566*9acbbeafSnn35248 * if we're not actively exiting it impossible for another 567*9acbbeafSnn35248 * thread in this process to be exiting. (Because that 568*9acbbeafSnn35248 * thread would have already stopped all other threads 569*9acbbeafSnn35248 * in the current process.) 570*9acbbeafSnn35248 */ 571*9acbbeafSnn35248 ASSERT(at_exit || !sp->s_exit); 572*9acbbeafSnn35248 573*9acbbeafSnn35248 /* 574*9acbbeafSnn35248 * If no one else has a hold on this session structure 575*9acbbeafSnn35248 * then we now have exclusive access to it, so break out 576*9acbbeafSnn35248 * of this loop and update the session structure. 577*9acbbeafSnn35248 */ 578*9acbbeafSnn35248 if (sp->s_cnt == 0) 579*9acbbeafSnn35248 break; 580*9acbbeafSnn35248 581*9acbbeafSnn35248 if (!at_exit) { 582*9acbbeafSnn35248 /* need to hold the session so it can't be freed */ 583*9acbbeafSnn35248 sp->s_ref++; 584*9acbbeafSnn35248 } 585*9acbbeafSnn35248 586*9acbbeafSnn35248 /* ain't locking order fun? */ 587*9acbbeafSnn35248 mutex_exit(&p->p_splock); 588*9acbbeafSnn35248 mutex_exit(&pidlock); 589*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 590*9acbbeafSnn35248 591*9acbbeafSnn35248 if (at_exit) { 592*9acbbeafSnn35248 /* 593*9acbbeafSnn35248 * if we're exiting then we can't allow this operation 594*9acbbeafSnn35248 * to fail so we do a cw_wait() instead of a 595*9acbbeafSnn35248 * cv_wait_sig(). if there are threads with active 596*9acbbeafSnn35248 * holds on this ctty that are blocked, then 597*9acbbeafSnn35248 * they should only be blocked in a cv_wait_sig() 598*9acbbeafSnn35248 * and hopefully they were in the foreground process 599*9acbbeafSnn35248 * group and recieved the SIGHUP we sent above. of 600*9acbbeafSnn35248 * course it's possible that they weren't in the 601*9acbbeafSnn35248 * foreground process group and didn't get our 602*9acbbeafSnn35248 * signal (or they could be stopped by job control 603*9acbbeafSnn35248 * in which case our signal wouldn't matter until 604*9acbbeafSnn35248 * they are restarted). in this case we won't 605*9acbbeafSnn35248 * exit until someone else sends them a signal. 606*9acbbeafSnn35248 */ 607*9acbbeafSnn35248 cv_wait(&sp->s_cnt_cv, &sp->s_lock); 608*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 609*9acbbeafSnn35248 continue; 610*9acbbeafSnn35248 } 611*9acbbeafSnn35248 612*9acbbeafSnn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) { 613*9acbbeafSnn35248 got_sig = B_TRUE; 614*9acbbeafSnn35248 } 615*9acbbeafSnn35248 616*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 617*9acbbeafSnn35248 sess_rele(sp, B_FALSE); 618*9acbbeafSnn35248 619*9acbbeafSnn35248 if (got_sig) 620*9acbbeafSnn35248 return (EINTR); 621*9acbbeafSnn35248 } 622*9acbbeafSnn35248 ASSERT(sp->s_cnt == 0); 623*9acbbeafSnn35248 624*9acbbeafSnn35248 /* save some pointers for later */ 625*9acbbeafSnn35248 cred = sp->s_cred; 626*9acbbeafSnn35248 pgidp = stp->sd_pgidp; 627*9acbbeafSnn35248 sidp = stp->sd_sidp; 628*9acbbeafSnn35248 629*9acbbeafSnn35248 /* clear the session ctty bindings */ 630*9acbbeafSnn35248 sess_ctty_clear(sp, stp); 631*9acbbeafSnn35248 632*9acbbeafSnn35248 /* wake up anyone blocked in tty_hold() */ 633*9acbbeafSnn35248 if (at_exit) { 634*9acbbeafSnn35248 ASSERT(sp->s_exit); 635*9acbbeafSnn35248 sp->s_exit = B_FALSE; 636*9acbbeafSnn35248 cv_broadcast(&sp->s_exit_cv); 637*9acbbeafSnn35248 } 638*9acbbeafSnn35248 639*9acbbeafSnn35248 /* we can drop these locks now */ 640*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 641*9acbbeafSnn35248 mutex_exit(&p->p_splock); 642*9acbbeafSnn35248 mutex_exit(&pidlock); 643*9acbbeafSnn35248 mutex_exit(&stp->sd_lock); 644*9acbbeafSnn35248 645*9acbbeafSnn35248 /* This is the only remaining thread with access to this vnode */ 6467c478bd9Sstevel@tonic-gate (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred); 6477c478bd9Sstevel@tonic-gate VN_RELE(vp); 6487c478bd9Sstevel@tonic-gate crfree(cred); 649*9acbbeafSnn35248 650*9acbbeafSnn35248 /* release our holds on assorted structures and return */ 651*9acbbeafSnn35248 mutex_enter(&pidlock); 652*9acbbeafSnn35248 PID_RELE(pgidp); 653*9acbbeafSnn35248 PID_RELE(sidp); 654*9acbbeafSnn35248 mutex_exit(&pidlock); 655*9acbbeafSnn35248 656*9acbbeafSnn35248 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 { 683*9acbbeafSnn35248 sess_t *sp; 684*9acbbeafSnn35248 dev_t dev; 685*9acbbeafSnn35248 686*9acbbeafSnn35248 mutex_enter(&pp->p_splock); /* protects p->p_sessp */ 687*9acbbeafSnn35248 sp = pp->p_sessp; 688*9acbbeafSnn35248 689*9acbbeafSnn35248 #ifdef DEBUG 690*9acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 6917c478bd9Sstevel@tonic-gate if (sp->s_vp == NULL) 692*9acbbeafSnn35248 ASSERT(sp->s_dev == NODEV); 693*9acbbeafSnn35248 else 694*9acbbeafSnn35248 ASSERT(sp->s_dev != NODEV); 695*9acbbeafSnn35248 mutex_exit(&sp->s_lock); 696*9acbbeafSnn35248 #endif /* DEBUG */ 697*9acbbeafSnn35248 698*9acbbeafSnn35248 dev = sp->s_dev; 699*9acbbeafSnn35248 mutex_exit(&pp->p_splock); 700*9acbbeafSnn35248 return (dev); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate void 704*9acbbeafSnn35248 ctty_clear_sighuped(void) 7057c478bd9Sstevel@tonic-gate { 706*9acbbeafSnn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock)); 707*9acbbeafSnn35248 curproc->p_sessp->s_sighuped = B_FALSE; 7087c478bd9Sstevel@tonic-gate } 709