1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 #include <sys/types.h>
  33 #include <sys/sysmacros.h>
  34 #include <sys/param.h>
  35 #include <sys/systm.h>
  36 #include <sys/file.h>
  37 #include <sys/vnode.h>
  38 #include <sys/errno.h>
  39 #include <sys/signal.h>
  40 #include <sys/cred.h>
  41 #include <sys/policy.h>
  42 #include <sys/conf.h>
  43 #include <sys/debug.h>
  44 #include <sys/proc.h>
  45 #include <sys/session.h>
  46 #include <sys/kmem.h>
  47 #include <sys/cmn_err.h>
  48 #include <sys/strsubr.h>
  49 #include <sys/fs/snode.h>
  50 
  51 sess_t session0 = {
  52         &pid0,              /* s_sidp */
  53         {0},            /* s_lock */
  54         1,              /* s_ref */
  55         B_FALSE,        /* s_sighuped */
  56         B_FALSE,        /* s_exit */
  57         0,              /* s_exit_cv */
  58         0,              /* s_cnt */
  59         0,              /* s_cnt_cv */
  60         NODEV,          /* s_dev */
  61         NULL,           /* s_vp */
  62         NULL            /* s_cred */
  63 };
  64 
  65 void
  66 sess_hold(proc_t *p)
  67 {
  68         ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
  69         mutex_enter(&p->p_sessp->s_lock);
  70         p->p_sessp->s_ref++;
  71         mutex_exit(&p->p_sessp->s_lock);
  72 }
  73 
  74 void
  75 sess_rele(sess_t *sp, boolean_t pidlock_held)
  76 {
  77         ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
  78 
  79         mutex_enter(&sp->s_lock);
  80 
  81         ASSERT(sp->s_ref != 0);
  82         if (--sp->s_ref > 0) {
  83                 mutex_exit(&sp->s_lock);
  84                 return;
  85         }
  86         ASSERT(sp->s_ref == 0);
  87 
  88         /*
  89          * It's ok to free this session structure now because we know
  90          * that no one else can have a pointer to it.  We know this
  91          * to be true because the only time that s_ref can possibly
  92          * be incremented is when pidlock or p_splock is held AND there
  93          * is a proc_t that points to that session structure.  In that
  94          * case we are guaranteed that the s_ref is at least 1 since there
  95          * is a proc_t that points to it.  So when s_ref finally drops to
  96          * zero then no one else has a reference (and hence pointer) to
  97          * this session structure and there is no valid proc_t pointing
  98          * to this session structure anymore so, no one can acquire a
  99          * reference (and pointer) to this session structure so it's
 100          * ok to free it here.
 101          */
 102 
 103         if (sp == &session0)
 104                 panic("sp == &session0");
 105 
 106         /* make sure there are no outstanding holds */
 107         ASSERT(sp->s_cnt == 0);
 108 
 109         /* make sure there is no exit in progress */
 110         ASSERT(!sp->s_exit);
 111 
 112         /* make sure someone already freed any ctty */
 113         ASSERT(sp->s_vp == NULL);
 114         ASSERT(sp->s_dev == NODEV);
 115 
 116         if (!pidlock_held)
 117                 mutex_enter(&pidlock);
 118         PID_RELE(sp->s_sidp);
 119         if (!pidlock_held)
 120                 mutex_exit(&pidlock);
 121 
 122         mutex_destroy(&sp->s_lock);
 123         cv_destroy(&sp->s_cnt_cv);
 124         kmem_free(sp, sizeof (sess_t));
 125 }
 126 
 127 sess_t *
 128 tty_hold(void)
 129 {
 130         proc_t          *p = curproc;
 131         sess_t          *sp;
 132         boolean_t       got_sig = B_FALSE;
 133 
 134         /* make sure the caller isn't holding locks they shouldn't */
 135         ASSERT(MUTEX_NOT_HELD(&pidlock));
 136 
 137         for (;;) {
 138                 mutex_enter(&p->p_splock);       /* protect p->p_sessp */
 139                 sp = p->p_sessp;
 140                 mutex_enter(&sp->s_lock);        /* protect sp->* */
 141 
 142                 /* make sure the caller isn't holding locks they shouldn't */
 143                 ASSERT((sp->s_vp == NULL) ||
 144                     MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
 145 
 146                 /*
 147                  * If the session leader process is not exiting (and hence
 148                  * not trying to release the session's ctty) then we can
 149                  * safely grab a hold on the current session structure
 150                  * and return it.  If on the other hand the session leader
 151                  * process is exiting and clearing the ctty then we'll
 152                  * wait till it's done before we loop around and grab a
 153                  * hold on the session structure.
 154                  */
 155                 if (!sp->s_exit)
 156                         break;
 157 
 158                 /* need to hold the session so it can't be freed */
 159                 sp->s_ref++;
 160                 mutex_exit(&p->p_splock);
 161 
 162                 /* Wait till the session leader is done */
 163                 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
 164                         got_sig = B_TRUE;
 165 
 166                 /*
 167                  * Now we need to drop our hold on the session structure,
 168                  * but we can't hold any locks when we do this because
 169                  * sess_rele() may need to acquire pidlock.
 170                  */
 171                 mutex_exit(&sp->s_lock);
 172                 sess_rele(sp, B_FALSE);
 173 
 174                 if (got_sig)
 175                         return (NULL);
 176         }
 177 
 178         /* whew, we finally got a hold */
 179         sp->s_cnt++;
 180         sp->s_ref++;
 181         mutex_exit(&sp->s_lock);
 182         mutex_exit(&p->p_splock);
 183         return (sp);
 184 }
 185 
 186 void
 187 tty_rele(sess_t *sp)
 188 {
 189         /* make sure the caller isn't holding locks they shouldn't */
 190         ASSERT(MUTEX_NOT_HELD(&pidlock));
 191 
 192         mutex_enter(&sp->s_lock);
 193         if ((--sp->s_cnt) == 0)
 194                 cv_broadcast(&sp->s_cnt_cv);
 195         mutex_exit(&sp->s_lock);
 196 
 197         sess_rele(sp, B_FALSE);
 198 }
 199 
 200 void
 201 sess_create(void)
 202 {
 203         proc_t *p = curproc;
 204         sess_t *sp, *old_sp;
 205 
 206         sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP);
 207 
 208         mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
 209         cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
 210 
 211         /*
 212          * we need to grap p_lock to protect p_pgidp because
 213          * /proc looks at p_pgidp while holding only p_lock.
 214          *
 215          * we don't need to hold p->p_sessp->s_lock or get a hold on the
 216          * session structure since we're not actually updating any of
 217          * the contents of the old session structure.
 218          */
 219         mutex_enter(&pidlock);
 220         mutex_enter(&p->p_lock);
 221         mutex_enter(&p->p_splock);
 222 
 223         pgexit(p);
 224 
 225         sp->s_sidp = p->p_pidp;
 226         sp->s_ref = 1;
 227         sp->s_dev = NODEV;
 228 
 229         old_sp = p->p_sessp;
 230         p->p_sessp = sp;
 231 
 232         pgjoin(p, p->p_pidp);
 233         PID_HOLD(p->p_pidp);
 234 
 235         mutex_exit(&p->p_splock);
 236         mutex_exit(&p->p_lock);
 237         mutex_exit(&pidlock);
 238 
 239         sess_rele(old_sp, B_FALSE);
 240 }
 241 
 242 /*
 243  * Note that sess_ctty_clear() resets all the fields in the session
 244  * structure but doesn't release any holds or free any objects
 245  * that the session structure might currently point to.  it is the
 246  * callers responsibility to do this.
 247  */
 248 static void
 249 sess_ctty_clear(sess_t *sp, stdata_t *stp)
 250 {
 251         /*
 252          * Assert that we hold all the necessary locks.  We also need
 253          * to be holding proc_t->p_splock for the process associated
 254          * with this session, but since we don't have a proc pointer
 255          * passed in we can't assert this here.
 256          */
 257         ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
 258             MUTEX_HELD(&sp->s_lock));
 259 
 260         /* reset the session structure members to defaults */
 261         sp->s_sighuped = B_FALSE;
 262         sp->s_dev = NODEV;
 263         sp->s_vp = NULL;
 264         sp->s_cred = NULL;
 265 
 266         /* reset the stream session and group pointers */
 267         stp->sd_pgidp = NULL;
 268         stp->sd_sidp = NULL;
 269 }
 270 
 271 static void
 272 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
 273 {
 274         cred_t  *crp;
 275 
 276         /* Assert that we hold all the necessary locks. */
 277         ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
 278             MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
 279 
 280         /* get holds on structures */
 281         mutex_enter(&p->p_crlock);
 282         crhold(crp = p->p_cred);
 283         mutex_exit(&p->p_crlock);
 284         PID_HOLD(sp->s_sidp);        /* requires pidlock */
 285         PID_HOLD(sp->s_sidp);        /* requires pidlock */
 286 
 287         /* update the session structure members */
 288         sp->s_vp = makectty(stp->sd_vnode);
 289         sp->s_dev = sp->s_vp->v_rdev;
 290         sp->s_cred = crp;
 291 
 292         /* update the stream emebers */
 293         stp->sd_flag |= STRISTTY;    /* just to be sure */
 294         stp->sd_sidp = sp->s_sidp;
 295         stp->sd_pgidp = sp->s_sidp;
 296 }
 297 
 298 int
 299 strctty(stdata_t *stp)
 300 {
 301         sess_t          *sp;
 302         proc_t          *p = curproc;
 303         boolean_t       got_sig = B_FALSE;
 304 
 305         /*
 306          * We are going to try to make stp the default ctty for the session
 307          * associated with curproc.  Not only does this require holding a
 308          * bunch of locks but it also requires waiting for any outstanding
 309          * holds on the session structure (acquired via tty_hold()) to be
 310          * released.  Hence, we have the following for(;;) loop that will
 311          * acquire our locks, do some sanity checks, and wait for the hold
 312          * count on the session structure to hit zero.  If we get a signal
 313          * while waiting for outstanding holds to be released then we abort
 314          * the operation and return.
 315          */
 316         for (;;) {
 317                 mutex_enter(&stp->sd_lock);      /* protects sd_pgidp/sd_sidp */
 318                 mutex_enter(&pidlock);              /* protects p_pidp */
 319                 mutex_enter(&p->p_splock);       /* protects p_sessp */
 320                 sp = p->p_sessp;
 321                 mutex_enter(&sp->s_lock);        /* protects sp->* */
 322 
 323                 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
 324                     (stp->sd_sidp != NULL) ||                /* stp already ctty? */
 325                     (p->p_pidp != sp->s_sidp) ||  /* we're not leader? */
 326                     (sp->s_vp != NULL)) {            /* session has ctty? */
 327                         mutex_exit(&sp->s_lock);
 328                         mutex_exit(&p->p_splock);
 329                         mutex_exit(&pidlock);
 330                         mutex_exit(&stp->sd_lock);
 331                         return (ENOTTY);
 332                 }
 333 
 334                 /* sanity check.  we can't be exiting right now */
 335                 ASSERT(!sp->s_exit);
 336 
 337                 /*
 338                  * If no one else has a hold on this session structure
 339                  * then we now have exclusive access to it, so break out
 340                  * of this loop and update the session structure.
 341                  */
 342                 if (sp->s_cnt == 0)
 343                         break;
 344 
 345                 /* need to hold the session so it can't be freed */
 346                 sp->s_ref++;
 347 
 348                 /* ain't locking order fun? */
 349                 mutex_exit(&p->p_splock);
 350                 mutex_exit(&pidlock);
 351                 mutex_exit(&stp->sd_lock);
 352 
 353                 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
 354                         got_sig = B_TRUE;
 355                 mutex_exit(&sp->s_lock);
 356                 sess_rele(sp, B_FALSE);
 357 
 358                 if (got_sig)
 359                         return (EINTR);
 360         }
 361 
 362         /* set the session ctty bindings */
 363         sess_ctty_set(p, sp, stp);
 364 
 365         mutex_exit(&sp->s_lock);
 366         mutex_exit(&p->p_splock);
 367         mutex_exit(&pidlock);
 368         mutex_exit(&stp->sd_lock);
 369         return (0);
 370 }
 371 
 372 /*
 373  * freectty_lock() attempts to acquire the army of locks required to free
 374  * the ctty associated with a given session leader process.  If it returns
 375  * successfully the following locks will be held:
 376  *      sd_lock, pidlock, p_splock, s_lock
 377  *
 378  * as a secondary bit of convenience, freectty_lock() will also return
 379  * pointers to the session, ctty, and ctty stream associated with the
 380  * specified session leader process.
 381  */
 382 static boolean_t
 383 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
 384     boolean_t at_exit)
 385 {
 386         sess_t          *sp;
 387         vnode_t         *vp;
 388         stdata_t        *stp;
 389 
 390         mutex_enter(&pidlock);                      /* protect p_pidp */
 391         mutex_enter(&p->p_splock);               /* protect p->p_sessp */
 392         sp = p->p_sessp;
 393         mutex_enter(&sp->s_lock);                /* protect sp->* */
 394 
 395         if ((sp->s_sidp != p->p_pidp) ||  /* we're not leader? */
 396             (sp->s_vp == NULL)) {            /* no ctty? */
 397                 mutex_exit(&sp->s_lock);
 398                 mutex_exit(&p->p_splock);
 399                 mutex_exit(&pidlock);
 400                 return (B_FALSE);
 401         }
 402 
 403         vp = sp->s_vp;
 404         stp = sp->s_vp->v_stream;
 405 
 406         if (at_exit) {
 407                 /* stop anyone else calling tty_hold() */
 408                 sp->s_exit = B_TRUE;
 409         } else {
 410                 /*
 411                  * due to locking order we have to grab stp->sd_lock before
 412                  * grabbing all the other proc/session locks.  but after we
 413                  * drop all our current locks it's possible that someone
 414                  * could come in and change our current session or close
 415                  * the current ctty (vp) there by making sp or stp invalid.
 416                  * (a VN_HOLD on vp won't protect stp because that only
 417                  * prevents the vnode from being freed not closed.)  so
 418                  * to prevent this we bump s_ref and s_cnt here.
 419                  *
 420                  * course this doesn't matter if we're the last thread in
 421                  * an exiting process that is the session leader, since no
 422                  * one else can change our session or free our ctty.
 423                  */
 424                 sp->s_ref++; /* hold the session structure */
 425                 sp->s_cnt++; /* protect vp and stp */
 426         }
 427 
 428         /* drop our session locks */
 429         mutex_exit(&sp->s_lock);
 430         mutex_exit(&p->p_splock);
 431         mutex_exit(&pidlock);
 432 
 433         /* grab locks in the right order */
 434         mutex_enter(&stp->sd_lock);              /* protects sd_pgidp/sd_sidp */
 435         mutex_enter(&pidlock);                      /* protect p_pidp */
 436         mutex_enter(&p->p_splock);               /* protects p->p_sessp */
 437         mutex_enter(&sp->s_lock);                /* protects sp->* */
 438 
 439         /* if the session has changed, abort mission */
 440         if (sp != p->p_sessp) {
 441                 /*
 442                  * this can't happen during process exit since we're the
 443                  * only thread in the process and we sure didn't change
 444                  * our own session at this point.
 445                  */
 446                 ASSERT(!at_exit);
 447 
 448                 /* release our locks and holds */
 449                 mutex_exit(&sp->s_lock);
 450                 mutex_exit(&p->p_splock);
 451                 mutex_exit(&pidlock);
 452                 mutex_exit(&stp->sd_lock);
 453                 tty_rele(sp);
 454                 return (B_FALSE);
 455         }
 456 
 457         /*
 458          * sanity checks.  none of this should have changed since we had
 459          * holds on the current ctty.
 460          */
 461         ASSERT(sp->s_sidp == p->p_pidp);  /* we're the leader */
 462         ASSERT(sp->s_vp != NULL);            /* a ctty exists */
 463         ASSERT(vp == sp->s_vp);
 464         ASSERT(stp == sp->s_vp->v_stream);
 465 
 466         /* release our holds */
 467         if (!at_exit) {
 468                 if ((--(sp)->s_cnt) == 0)
 469                         cv_broadcast(&sp->s_cnt_cv);
 470                 sp->s_ref--;
 471                 ASSERT(sp->s_ref > 0);
 472         }
 473 
 474         /* return our pointers */
 475         *spp = sp;
 476         *vpp = vp;
 477         *stpp = stp;
 478 
 479         return (B_TRUE);
 480 }
 481 
 482 /*
 483  * Returns B_FALSE if no signal is sent to the process group associated with
 484  * this ctty.  Returns B_TRUE if a signal is sent to the process group.
 485  * If it return B_TRUE it also means that all the locks we were holding
 486  * were dropped so that we could send the signal.
 487  */
 488 static boolean_t
 489 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
 490 {
 491         /* Assert that we hold all the necessary locks. */
 492         ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
 493             MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
 494 
 495         /* check if we already signaled this group */
 496         if (sp->s_sighuped)
 497                 return (B_FALSE);
 498 
 499         sp->s_sighuped = B_TRUE;
 500 
 501         if (!at_exit) {
 502                 /*
 503                  * once again, we're about to drop our army of locks and we
 504                  * don't want sp or stp to be freed.  (see the comment in
 505                  * freectty_lock())
 506                  */
 507                 sp->s_ref++; /* hold the session structure */
 508                 sp->s_cnt++; /* protect vp and stp */
 509         }
 510 
 511         /* can't hold these locks while calling pgsignal() */
 512         mutex_exit(&sp->s_lock);
 513         mutex_exit(&p->p_splock);
 514         mutex_exit(&pidlock);
 515 
 516         /* signal anyone in the foreground process group */
 517         pgsignal(stp->sd_pgidp, SIGHUP);
 518 
 519         /* signal anyone blocked in poll on this stream */
 520         if (!(stp->sd_flag & STRHUP))
 521                 strhup(stp);
 522 
 523         mutex_exit(&stp->sd_lock);
 524 
 525         /* release our holds */
 526         if (!at_exit)
 527                 tty_rele(sp);
 528 
 529         return (B_TRUE);
 530 }
 531 
 532 int
 533 freectty(boolean_t at_exit)
 534 {
 535         proc_t          *p = curproc;
 536         stdata_t        *stp;
 537         vnode_t         *vp;
 538         cred_t          *cred;
 539         sess_t          *sp;
 540         struct pid      *pgidp, *sidp;
 541         boolean_t       got_sig = B_FALSE;
 542 
 543         /*
 544          * If the current process is a session leader we are going to
 545          * try to release the ctty associated our current session.  To
 546          * do this we need to acquire a bunch of locks, signal any
 547          * processes in the forground that are associated with the ctty,
 548          * and make sure no one has any outstanding holds on the current
 549          * session * structure (acquired via tty_hold()).  Hence, we have
 550          * the following for(;;) loop that will do all this work for
 551          * us and break out when the hold count on the session structure
 552          * hits zero.
 553          */
 554         for (;;) {
 555                 if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
 556                         return (EIO);
 557 
 558                 if (freectty_signal(p, sp, stp, at_exit)) {
 559                         /* loop around to re-acquire locks */
 560                         continue;
 561                 }
 562 
 563                 /*
 564                  * Only a session leader process can free a ctty.  So if
 565                  * we've made it here we know we're a session leader and
 566                  * if we're not actively exiting it impossible for another
 567                  * thread in this process to be exiting.  (Because that
 568                  * thread would have already stopped all other threads
 569                  * in the current process.)
 570                  */
 571                 ASSERT(at_exit || !sp->s_exit);
 572 
 573                 /*
 574                  * If no one else has a hold on this session structure
 575                  * then we now have exclusive access to it, so break out
 576                  * of this loop and update the session structure.
 577                  */
 578                 if (sp->s_cnt == 0)
 579                         break;
 580 
 581                 if (!at_exit) {
 582                         /* need to hold the session so it can't be freed */
 583                         sp->s_ref++;
 584                 }
 585 
 586                 /* ain't locking order fun? */
 587                 mutex_exit(&p->p_splock);
 588                 mutex_exit(&pidlock);
 589                 mutex_exit(&stp->sd_lock);
 590 
 591                 if (at_exit) {
 592                         /*
 593                          * if we're exiting then we can't allow this operation
 594                          * to fail so we do a cw_wait() instead of a
 595                          * cv_wait_sig().  if there are threads with active
 596                          * holds on this ctty that are blocked, then
 597                          * they should only be blocked in a cv_wait_sig()
 598                          * and hopefully they were in the foreground process
 599                          * group and recieved the SIGHUP we sent above.  of
 600                          * course it's possible that they weren't in the
 601                          * foreground process group and didn't get our
 602                          * signal (or they could be stopped by job control
 603                          * in which case our signal wouldn't matter until
 604                          * they are restarted).  in this case we won't
 605                          * exit until someone else sends them a signal.
 606                          */
 607                         cv_wait(&sp->s_cnt_cv, &sp->s_lock);
 608                         mutex_exit(&sp->s_lock);
 609                         continue;
 610                 }
 611 
 612                 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
 613                         got_sig = B_TRUE;
 614                 }
 615 
 616                 mutex_exit(&sp->s_lock);
 617                 sess_rele(sp, B_FALSE);
 618 
 619                 if (got_sig)
 620                         return (EINTR);
 621         }
 622         ASSERT(sp->s_cnt == 0);
 623 
 624         /* save some pointers for later */
 625         cred = sp->s_cred;
 626         pgidp = stp->sd_pgidp;
 627         sidp = stp->sd_sidp;
 628 
 629         /* clear the session ctty bindings */
 630         sess_ctty_clear(sp, stp);
 631 
 632         /* wake up anyone blocked in tty_hold() */
 633         if (at_exit) {
 634                 ASSERT(sp->s_exit);
 635                 sp->s_exit = B_FALSE;
 636                 cv_broadcast(&sp->s_exit_cv);
 637         }
 638 
 639         /* we can drop these locks now */
 640         mutex_exit(&sp->s_lock);
 641         mutex_exit(&p->p_splock);
 642         mutex_exit(&pidlock);
 643         mutex_exit(&stp->sd_lock);
 644 
 645         /* This is the only remaining thread with access to this vnode */
 646         (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
 647         VN_RELE(vp);
 648         crfree(cred);
 649 
 650         /* release our holds on assorted structures and return */
 651         mutex_enter(&pidlock);
 652         PID_RELE(pgidp);
 653         PID_RELE(sidp);
 654         mutex_exit(&pidlock);
 655 
 656         return (1);
 657 }
 658 
 659 /*
 660  *      ++++++++++++++++++++++++
 661  *      ++  SunOS4.1 Buyback  ++
 662  *      ++++++++++++++++++++++++
 663  *
 664  * vhangup: Revoke access of the current tty by all processes
 665  * Used by privileged users to give a "clean" terminal at login
 666  */
 667 int
 668 vhangup(void)
 669 {
 670         if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
 671                 return (set_errno(EPERM));
 672         /*
 673          * This routine used to call freectty() under a condition that
 674          * could never happen.  So this code has never actually done
 675          * anything, and evidently nobody has ever noticed.
 676          */
 677         return (0);
 678 }
 679 
 680 dev_t
 681 cttydev(proc_t *pp)
 682 {
 683         sess_t  *sp;
 684         dev_t   dev;
 685 
 686         mutex_enter(&pp->p_splock);      /* protects p->p_sessp */
 687         sp = pp->p_sessp;
 688 
 689 #ifdef DEBUG
 690         mutex_enter(&sp->s_lock);        /* protects sp->* */
 691         if (sp->s_vp == NULL)
 692                 ASSERT(sp->s_dev == NODEV);
 693         else
 694                 ASSERT(sp->s_dev != NODEV);
 695         mutex_exit(&sp->s_lock);
 696 #endif /* DEBUG */
 697 
 698         dev = sp->s_dev;
 699         mutex_exit(&pp->p_splock);
 700         return (dev);
 701 }
 702 
 703 void
 704 ctty_clear_sighuped(void)
 705 {
 706         ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
 707         curproc->p_sessp->s_sighuped = B_FALSE;
 708 }