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