sys_term.c revision 29181
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 36#endif /* not lint */ 37 38#include "telnetd.h" 39#include "pathnames.h" 40 41#if defined(AUTHENTICATION) 42#include <libtelnet/auth.h> 43#endif 44 45extern char *altlogin; 46int cleanopen(char *line); 47void scrub_env(void); 48 49#if defined(CRAY) || defined(__hpux) 50# define PARENT_DOES_UTMP 51#endif 52 53int utmp_len = MAXHOSTNAMELEN; 54#ifdef NEWINIT 55#include <initreq.h> 56#else /* NEWINIT*/ 57# ifdef UTMPX 58# include <utmpx.h> 59struct utmpx wtmp; 60# else 61# include <utmp.h> 62struct utmp wtmp; 63# endif /* UTMPX */ 64 65# ifndef PARENT_DOES_UTMP 66#ifdef _PATH_WTMP 67char wtmpf[] = _PATH_WTMP; 68#else 69char wtmpf[] = "/usr/adm/wtmp"; 70#endif 71#ifdef _PATH_UTMP 72char utmpf[] = _PATH_UTMP; 73#else 74char utmpf[] = "/etc/utmp"; 75#endif 76# else /* PARENT_DOES_UTMP */ 77char wtmpf[] = "/etc/wtmp"; 78# endif /* PARENT_DOES_UTMP */ 79 80#include <libutil.h> 81 82# ifdef CRAY 83#include <tmpdir.h> 84#include <sys/wait.h> 85# if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1') 86# define UNICOS7x 87# endif 88 89# ifdef UNICOS7x 90#include <sys/sysv.h> 91#include <sys/secstat.h> 92extern int secflag; 93extern struct sysv sysv; 94# endif /* UNICOS7x */ 95# endif /* CRAY */ 96#endif /* NEWINIT */ 97 98#ifdef STREAMSPTY 99#include <sac.h> 100#include <sys/stropts.h> 101#endif 102 103#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 104#define SCMPN(a, b) strncmp(a, b, sizeof(a)) 105 106#ifdef STREAMS 107#include <sys/stream.h> 108#endif 109#ifdef __hpux 110#include <sys/resource.h> 111#include <sys/proc.h> 112#endif 113#include <sys/tty.h> 114#ifdef t_erase 115#undef t_erase 116#undef t_kill 117#undef t_intrc 118#undef t_quitc 119#undef t_startc 120#undef t_stopc 121#undef t_eofc 122#undef t_brkc 123#undef t_suspc 124#undef t_dsuspc 125#undef t_rprntc 126#undef t_flushc 127#undef t_werasc 128#undef t_lnextc 129#endif 130 131#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC) 132# define EXTPROC 0400 133#endif 134 135#ifndef USE_TERMIO 136struct termbuf { 137 struct sgttyb sg; 138 struct tchars tc; 139 struct ltchars ltc; 140 int state; 141 int lflags; 142} termbuf, termbuf2; 143# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) 144# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) 145# define cfgetospeed(tp) (tp)->sg.sg_ospeed 146# define cfgetispeed(tp) (tp)->sg.sg_ispeed 147#else /* USE_TERMIO */ 148# ifdef SYSV_TERMIO 149# define termios termio 150# endif 151# ifndef TCSANOW 152# ifdef TCSETS 153# define TCSANOW TCSETS 154# define TCSADRAIN TCSETSW 155# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 156# else 157# ifdef TCSETA 158# define TCSANOW TCSETA 159# define TCSADRAIN TCSETAW 160# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 161# else 162# define TCSANOW TIOCSETA 163# define TCSADRAIN TIOCSETAW 164# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 165# endif 166# endif 167# define tcsetattr(f, a, t) ioctl(f, a, t) 168# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 169 (tp)->c_cflag |= (val) 170# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) 171# ifdef CIBAUD 172# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 173 (tp)->c_cflag |= ((val)<<IBSHIFT) 174# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) 175# else 176# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 177 (tp)->c_cflag |= (val) 178# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) 179# endif 180# endif /* TCSANOW */ 181struct termios termbuf, termbuf2; /* pty control structure */ 182# ifdef STREAMSPTY 183int ttyfd = -1; 184# endif 185#endif /* USE_TERMIO */ 186 187/* 188 * init_termbuf() 189 * copy_termbuf(cp) 190 * set_termbuf() 191 * 192 * These three routines are used to get and set the "termbuf" structure 193 * to and from the kernel. init_termbuf() gets the current settings. 194 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 195 * set_termbuf() writes the structure into the kernel. 196 */ 197 198 void 199init_termbuf() 200{ 201#ifndef USE_TERMIO 202 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); 203 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); 204 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); 205# ifdef TIOCGSTATE 206 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); 207# endif 208#else 209# ifdef STREAMSPTY 210 (void) tcgetattr(ttyfd, &termbuf); 211# else 212 (void) tcgetattr(pty, &termbuf); 213# endif 214#endif 215 termbuf2 = termbuf; 216} 217 218#if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 219 void 220copy_termbuf(cp, len) 221 char *cp; 222 int len; 223{ 224 if (len > sizeof(termbuf)) 225 len = sizeof(termbuf); 226 memmove((char *)&termbuf, cp, len); 227 termbuf2 = termbuf; 228} 229#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 230 231 void 232set_termbuf() 233{ 234 /* 235 * Only make the necessary changes. 236 */ 237#ifndef USE_TERMIO 238 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, 239 sizeof(termbuf.sg))) 240 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); 241 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, 242 sizeof(termbuf.tc))) 243 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); 244 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, 245 sizeof(termbuf.ltc))) 246 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); 247 if (termbuf.lflags != termbuf2.lflags) 248 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); 249#else /* USE_TERMIO */ 250 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 251# ifdef STREAMSPTY 252 (void) tcsetattr(ttyfd, TCSANOW, &termbuf); 253# else 254 (void) tcsetattr(pty, TCSANOW, &termbuf); 255# endif 256# if defined(CRAY2) && defined(UNICOS5) 257 needtermstat = 1; 258# endif 259#endif /* USE_TERMIO */ 260} 261 262 263/* 264 * spcset(func, valp, valpp) 265 * 266 * This function takes various special characters (func), and 267 * sets *valp to the current value of that character, and 268 * *valpp to point to where in the "termbuf" structure that 269 * value is kept. 270 * 271 * It returns the SLC_ level of support for this function. 272 */ 273 274#ifndef USE_TERMIO 275 int 276spcset(func, valp, valpp) 277 int func; 278 cc_t *valp; 279 cc_t **valpp; 280{ 281 switch(func) { 282 case SLC_EOF: 283 *valp = termbuf.tc.t_eofc; 284 *valpp = (cc_t *)&termbuf.tc.t_eofc; 285 return(SLC_VARIABLE); 286 case SLC_EC: 287 *valp = termbuf.sg.sg_erase; 288 *valpp = (cc_t *)&termbuf.sg.sg_erase; 289 return(SLC_VARIABLE); 290 case SLC_EL: 291 *valp = termbuf.sg.sg_kill; 292 *valpp = (cc_t *)&termbuf.sg.sg_kill; 293 return(SLC_VARIABLE); 294 case SLC_IP: 295 *valp = termbuf.tc.t_intrc; 296 *valpp = (cc_t *)&termbuf.tc.t_intrc; 297 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 298 case SLC_ABORT: 299 *valp = termbuf.tc.t_quitc; 300 *valpp = (cc_t *)&termbuf.tc.t_quitc; 301 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 302 case SLC_XON: 303 *valp = termbuf.tc.t_startc; 304 *valpp = (cc_t *)&termbuf.tc.t_startc; 305 return(SLC_VARIABLE); 306 case SLC_XOFF: 307 *valp = termbuf.tc.t_stopc; 308 *valpp = (cc_t *)&termbuf.tc.t_stopc; 309 return(SLC_VARIABLE); 310 case SLC_AO: 311 *valp = termbuf.ltc.t_flushc; 312 *valpp = (cc_t *)&termbuf.ltc.t_flushc; 313 return(SLC_VARIABLE); 314 case SLC_SUSP: 315 *valp = termbuf.ltc.t_suspc; 316 *valpp = (cc_t *)&termbuf.ltc.t_suspc; 317 return(SLC_VARIABLE); 318 case SLC_EW: 319 *valp = termbuf.ltc.t_werasc; 320 *valpp = (cc_t *)&termbuf.ltc.t_werasc; 321 return(SLC_VARIABLE); 322 case SLC_RP: 323 *valp = termbuf.ltc.t_rprntc; 324 *valpp = (cc_t *)&termbuf.ltc.t_rprntc; 325 return(SLC_VARIABLE); 326 case SLC_LNEXT: 327 *valp = termbuf.ltc.t_lnextc; 328 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 329 return(SLC_VARIABLE); 330 case SLC_FORW1: 331 *valp = termbuf.tc.t_brkc; 332 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 333 return(SLC_VARIABLE); 334 case SLC_BRK: 335 case SLC_SYNCH: 336 case SLC_AYT: 337 case SLC_EOR: 338 *valp = (cc_t)0; 339 *valpp = (cc_t *)0; 340 return(SLC_DEFAULT); 341 default: 342 *valp = (cc_t)0; 343 *valpp = (cc_t *)0; 344 return(SLC_NOSUPPORT); 345 } 346} 347 348#else /* USE_TERMIO */ 349 350 int 351spcset(func, valp, valpp) 352 int func; 353 cc_t *valp; 354 cc_t **valpp; 355{ 356 357#define setval(a, b) *valp = termbuf.c_cc[a]; \ 358 *valpp = &termbuf.c_cc[a]; \ 359 return(b); 360#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 361 362 switch(func) { 363 case SLC_EOF: 364 setval(VEOF, SLC_VARIABLE); 365 case SLC_EC: 366 setval(VERASE, SLC_VARIABLE); 367 case SLC_EL: 368 setval(VKILL, SLC_VARIABLE); 369 case SLC_IP: 370 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 371 case SLC_ABORT: 372 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 373 case SLC_XON: 374#ifdef VSTART 375 setval(VSTART, SLC_VARIABLE); 376#else 377 defval(0x13); 378#endif 379 case SLC_XOFF: 380#ifdef VSTOP 381 setval(VSTOP, SLC_VARIABLE); 382#else 383 defval(0x11); 384#endif 385 case SLC_EW: 386#ifdef VWERASE 387 setval(VWERASE, SLC_VARIABLE); 388#else 389 defval(0); 390#endif 391 case SLC_RP: 392#ifdef VREPRINT 393 setval(VREPRINT, SLC_VARIABLE); 394#else 395 defval(0); 396#endif 397 case SLC_LNEXT: 398#ifdef VLNEXT 399 setval(VLNEXT, SLC_VARIABLE); 400#else 401 defval(0); 402#endif 403 case SLC_AO: 404#if !defined(VDISCARD) && defined(VFLUSHO) 405# define VDISCARD VFLUSHO 406#endif 407#ifdef VDISCARD 408 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 409#else 410 defval(0); 411#endif 412 case SLC_SUSP: 413#ifdef VSUSP 414 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 415#else 416 defval(0); 417#endif 418#ifdef VEOL 419 case SLC_FORW1: 420 setval(VEOL, SLC_VARIABLE); 421#endif 422#ifdef VEOL2 423 case SLC_FORW2: 424 setval(VEOL2, SLC_VARIABLE); 425#endif 426 case SLC_AYT: 427#ifdef VSTATUS 428 setval(VSTATUS, SLC_VARIABLE); 429#else 430 defval(0); 431#endif 432 433 case SLC_BRK: 434 case SLC_SYNCH: 435 case SLC_EOR: 436 defval(0); 437 438 default: 439 *valp = 0; 440 *valpp = 0; 441 return(SLC_NOSUPPORT); 442 } 443} 444#endif /* USE_TERMIO */ 445 446#ifdef CRAY 447/* 448 * getnpty() 449 * 450 * Return the number of pty's configured into the system. 451 */ 452 int 453getnpty() 454{ 455#ifdef _SC_CRAY_NPTY 456 int numptys; 457 458 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) 459 return numptys; 460 else 461#endif /* _SC_CRAY_NPTY */ 462 return 128; 463} 464#endif /* CRAY */ 465 466#ifndef convex 467/* 468 * getpty() 469 * 470 * Allocate a pty. As a side effect, the external character 471 * array "line" contains the name of the slave side. 472 * 473 * Returns the file descriptor of the opened pty. 474 */ 475#ifndef __GNUC__ 476char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 477#else 478static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 479char *line = Xline; 480#endif 481#ifdef CRAY 482char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 483#endif /* CRAY */ 484 485 int 486getpty(ptynum) 487int *ptynum; 488{ 489 register int p; 490#ifdef STREAMSPTY 491 int t; 492 char *ptsname(); 493 494 p = open("/dev/ptmx", 2); 495 if (p > 0) { 496 grantpt(p); 497 unlockpt(p); 498 strcpy(line, ptsname(p)); 499 return(p); 500 } 501 502#else /* ! STREAMSPTY */ 503#ifndef CRAY 504 register char *cp, *p1, *p2; 505 register int i; 506#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 507 int dummy; 508#endif 509 510#ifndef __hpux 511 (void) sprintf(line, "/dev/ptyXX"); 512 p1 = &line[8]; 513 p2 = &line[9]; 514#else 515 (void) sprintf(line, "/dev/ptym/ptyXX"); 516 p1 = &line[13]; 517 p2 = &line[14]; 518#endif 519 520 for (cp = "pqrsPQRS"; *cp; cp++) { 521 struct stat stb; 522 523 *p1 = *cp; 524 *p2 = '0'; 525 /* 526 * This stat() check is just to keep us from 527 * looping through all 256 combinations if there 528 * aren't that many ptys available. 529 */ 530 if (stat(line, &stb) < 0) 531 break; 532 for (i = 0; i < 32; i++) { 533 *p2 = "0123456789abcdefghijklmnopqrstuv"[i]; 534 p = open(line, 2); 535 if (p > 0) { 536#ifndef __hpux 537 line[5] = 't'; 538#else 539 for (p1 = &line[8]; *p1; p1++) 540 *p1 = *(p1+1); 541 line[9] = 't'; 542#endif 543 chown(line, 0, 0); 544 chmod(line, 0600); 545#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 546 if (ioctl(p, TIOCGPGRP, &dummy) == 0 547 || errno != EIO) { 548 chmod(line, 0666); 549 close(p); 550 line[5] = 'p'; 551 } else 552#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */ 553 return(p); 554 } 555 } 556 } 557#else /* CRAY */ 558 extern lowpty, highpty; 559 struct stat sb; 560 561 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { 562 (void) sprintf(myline, "/dev/pty/%03d", *ptynum); 563 p = open(myline, 2); 564 if (p < 0) 565 continue; 566 (void) sprintf(line, "/dev/ttyp%03d", *ptynum); 567 /* 568 * Here are some shenanigans to make sure that there 569 * are no listeners lurking on the line. 570 */ 571 if(stat(line, &sb) < 0) { 572 (void) close(p); 573 continue; 574 } 575 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { 576 chown(line, 0, 0); 577 chmod(line, 0600); 578 (void)close(p); 579 p = open(myline, 2); 580 if (p < 0) 581 continue; 582 } 583 /* 584 * Now it should be safe...check for accessability. 585 */ 586 if (access(line, 6) == 0) 587 return(p); 588 else { 589 /* no tty side to pty so skip it */ 590 (void) close(p); 591 } 592 } 593#endif /* CRAY */ 594#endif /* STREAMSPTY */ 595 return(-1); 596} 597#endif /* convex */ 598 599#ifdef LINEMODE 600/* 601 * tty_flowmode() Find out if flow control is enabled or disabled. 602 * tty_linemode() Find out if linemode (external processing) is enabled. 603 * tty_setlinemod(on) Turn on/off linemode. 604 * tty_isecho() Find out if echoing is turned on. 605 * tty_setecho(on) Enable/disable character echoing. 606 * tty_israw() Find out if terminal is in RAW mode. 607 * tty_binaryin(on) Turn on/off BINARY on input. 608 * tty_binaryout(on) Turn on/off BINARY on output. 609 * tty_isediting() Find out if line editing is enabled. 610 * tty_istrapsig() Find out if signal trapping is enabled. 611 * tty_setedit(on) Turn on/off line editing. 612 * tty_setsig(on) Turn on/off signal trapping. 613 * tty_issofttab() Find out if tab expansion is enabled. 614 * tty_setsofttab(on) Turn on/off soft tab expansion. 615 * tty_islitecho() Find out if typed control chars are echoed literally 616 * tty_setlitecho() Turn on/off literal echo of control chars 617 * tty_tspeed(val) Set transmit speed to val. 618 * tty_rspeed(val) Set receive speed to val. 619 */ 620 621#ifdef convex 622static int linestate; 623#endif 624 625 int 626tty_linemode() 627{ 628#ifndef convex 629#ifndef USE_TERMIO 630 return(termbuf.state & TS_EXTPROC); 631#else 632 return(termbuf.c_lflag & EXTPROC); 633#endif 634#else 635 return(linestate); 636#endif 637} 638 639 void 640tty_setlinemode(on) 641 int on; 642{ 643#ifdef TIOCEXT 644# ifndef convex 645 set_termbuf(); 646# else 647 linestate = on; 648# endif 649 (void) ioctl(pty, TIOCEXT, (char *)&on); 650# ifndef convex 651 init_termbuf(); 652# endif 653#else /* !TIOCEXT */ 654# ifdef EXTPROC 655 if (on) 656 termbuf.c_lflag |= EXTPROC; 657 else 658 termbuf.c_lflag &= ~EXTPROC; 659# endif 660#endif /* TIOCEXT */ 661} 662#endif /* LINEMODE */ 663 664 int 665tty_isecho() 666{ 667#ifndef USE_TERMIO 668 return (termbuf.sg.sg_flags & ECHO); 669#else 670 return (termbuf.c_lflag & ECHO); 671#endif 672} 673 674 int 675tty_flowmode() 676{ 677#ifndef USE_TERMIO 678 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); 679#else 680 return((termbuf.c_iflag & IXON) ? 1 : 0); 681#endif 682} 683 684 int 685tty_restartany() 686{ 687#ifndef USE_TERMIO 688# ifdef DECCTQ 689 return((termbuf.lflags & DECCTQ) ? 0 : 1); 690# else 691 return(-1); 692# endif 693#else 694 return((termbuf.c_iflag & IXANY) ? 1 : 0); 695#endif 696} 697 698 void 699tty_setecho(on) 700 int on; 701{ 702#ifndef USE_TERMIO 703 if (on) 704 termbuf.sg.sg_flags |= ECHO|CRMOD; 705 else 706 termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 707#else 708 if (on) 709 termbuf.c_lflag |= ECHO; 710 else 711 termbuf.c_lflag &= ~ECHO; 712#endif 713} 714 715 int 716tty_israw() 717{ 718#ifndef USE_TERMIO 719 return(termbuf.sg.sg_flags & RAW); 720#else 721 return(!(termbuf.c_lflag & ICANON)); 722#endif 723} 724 725#if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 726 int 727tty_setraw(on) 728{ 729# ifndef USE_TERMIO 730 if (on) 731 termbuf.sg.sg_flags |= RAW; 732 else 733 termbuf.sg.sg_flags &= ~RAW; 734# else 735 if (on) 736 termbuf.c_lflag &= ~ICANON; 737 else 738 termbuf.c_lflag |= ICANON; 739# endif 740} 741#endif 742 743 void 744tty_binaryin(on) 745 int on; 746{ 747#ifndef USE_TERMIO 748 if (on) 749 termbuf.lflags |= LPASS8; 750 else 751 termbuf.lflags &= ~LPASS8; 752#else 753 if (on) { 754 termbuf.c_iflag &= ~ISTRIP; 755 } else { 756 termbuf.c_iflag |= ISTRIP; 757 } 758#endif 759} 760 761 void 762tty_binaryout(on) 763 int on; 764{ 765#ifndef USE_TERMIO 766 if (on) 767 termbuf.lflags |= LLITOUT; 768 else 769 termbuf.lflags &= ~LLITOUT; 770#else 771 if (on) { 772 termbuf.c_cflag &= ~(CSIZE|PARENB); 773 termbuf.c_cflag |= CS8; 774 termbuf.c_oflag &= ~OPOST; 775 } else { 776 termbuf.c_cflag &= ~CSIZE; 777 termbuf.c_cflag |= CS7|PARENB; 778 termbuf.c_oflag |= OPOST; 779 } 780#endif 781} 782 783 int 784tty_isbinaryin() 785{ 786#ifndef USE_TERMIO 787 return(termbuf.lflags & LPASS8); 788#else 789 return(!(termbuf.c_iflag & ISTRIP)); 790#endif 791} 792 793 int 794tty_isbinaryout() 795{ 796#ifndef USE_TERMIO 797 return(termbuf.lflags & LLITOUT); 798#else 799 return(!(termbuf.c_oflag&OPOST)); 800#endif 801} 802 803#ifdef LINEMODE 804 int 805tty_isediting() 806{ 807#ifndef USE_TERMIO 808 return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 809#else 810 return(termbuf.c_lflag & ICANON); 811#endif 812} 813 814 int 815tty_istrapsig() 816{ 817#ifndef USE_TERMIO 818 return(!(termbuf.sg.sg_flags&RAW)); 819#else 820 return(termbuf.c_lflag & ISIG); 821#endif 822} 823 824 void 825tty_setedit(on) 826 int on; 827{ 828#ifndef USE_TERMIO 829 if (on) 830 termbuf.sg.sg_flags &= ~CBREAK; 831 else 832 termbuf.sg.sg_flags |= CBREAK; 833#else 834 if (on) 835 termbuf.c_lflag |= ICANON; 836 else 837 termbuf.c_lflag &= ~ICANON; 838#endif 839} 840 841 void 842tty_setsig(on) 843 int on; 844{ 845#ifndef USE_TERMIO 846 if (on) 847 ; 848#else 849 if (on) 850 termbuf.c_lflag |= ISIG; 851 else 852 termbuf.c_lflag &= ~ISIG; 853#endif 854} 855#endif /* LINEMODE */ 856 857 int 858tty_issofttab() 859{ 860#ifndef USE_TERMIO 861 return (termbuf.sg.sg_flags & XTABS); 862#else 863# ifdef OXTABS 864 return (termbuf.c_oflag & OXTABS); 865# endif 866# ifdef TABDLY 867 return ((termbuf.c_oflag & TABDLY) == TAB3); 868# endif 869#endif 870} 871 872 void 873tty_setsofttab(on) 874 int on; 875{ 876#ifndef USE_TERMIO 877 if (on) 878 termbuf.sg.sg_flags |= XTABS; 879 else 880 termbuf.sg.sg_flags &= ~XTABS; 881#else 882 if (on) { 883# ifdef OXTABS 884 termbuf.c_oflag |= OXTABS; 885# endif 886# ifdef TABDLY 887 termbuf.c_oflag &= ~TABDLY; 888 termbuf.c_oflag |= TAB3; 889# endif 890 } else { 891# ifdef OXTABS 892 termbuf.c_oflag &= ~OXTABS; 893# endif 894# ifdef TABDLY 895 termbuf.c_oflag &= ~TABDLY; 896 termbuf.c_oflag |= TAB0; 897# endif 898 } 899#endif 900} 901 902 int 903tty_islitecho() 904{ 905#ifndef USE_TERMIO 906 return (!(termbuf.lflags & LCTLECH)); 907#else 908# ifdef ECHOCTL 909 return (!(termbuf.c_lflag & ECHOCTL)); 910# endif 911# ifdef TCTLECH 912 return (!(termbuf.c_lflag & TCTLECH)); 913# endif 914# if !defined(ECHOCTL) && !defined(TCTLECH) 915 return (0); /* assumes ctl chars are echoed '^x' */ 916# endif 917#endif 918} 919 920 void 921tty_setlitecho(on) 922 int on; 923{ 924#ifndef USE_TERMIO 925 if (on) 926 termbuf.lflags &= ~LCTLECH; 927 else 928 termbuf.lflags |= LCTLECH; 929#else 930# ifdef ECHOCTL 931 if (on) 932 termbuf.c_lflag &= ~ECHOCTL; 933 else 934 termbuf.c_lflag |= ECHOCTL; 935# endif 936# ifdef TCTLECH 937 if (on) 938 termbuf.c_lflag &= ~TCTLECH; 939 else 940 termbuf.c_lflag |= TCTLECH; 941# endif 942#endif 943} 944 945 int 946tty_iscrnl() 947{ 948#ifndef USE_TERMIO 949 return (termbuf.sg.sg_flags & CRMOD); 950#else 951 return (termbuf.c_iflag & ICRNL); 952#endif 953} 954 955/* 956 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 957 */ 958#if B4800 != 4800 959#define DECODE_BAUD 960#endif 961 962#ifdef DECODE_BAUD 963 964/* 965 * A table of available terminal speeds 966 */ 967struct termspeeds { 968 int speed; 969 int value; 970} termspeeds[] = { 971 { 0, B0 }, { 50, B50 }, { 75, B75 }, 972 { 110, B110 }, { 134, B134 }, { 150, B150 }, 973 { 200, B200 }, { 300, B300 }, { 600, B600 }, 974 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 975 { 4800, B4800 }, 976#ifdef B7200 977 { 7200, B7200 }, 978#endif 979 { 9600, B9600 }, 980#ifdef B14400 981 { 14400, B14400 }, 982#endif 983#ifdef B19200 984 { 19200, B19200 }, 985#endif 986#ifdef B28800 987 { 28800, B28800 }, 988#endif 989#ifdef B38400 990 { 38400, B38400 }, 991#endif 992#ifdef B57600 993 { 57600, B57600 }, 994#endif 995#ifdef B115200 996 { 115200, B115200 }, 997#endif 998#ifdef B230400 999 { 230400, B230400 }, 1000#endif 1001 { -1, 0 } 1002}; 1003#endif /* DECODE_BUAD */ 1004 1005 void 1006tty_tspeed(val) 1007 int val; 1008{ 1009#ifdef DECODE_BAUD 1010 register struct termspeeds *tp; 1011 1012 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 1013 ; 1014 if (tp->speed == -1) /* back up to last valid value */ 1015 --tp; 1016 cfsetospeed(&termbuf, tp->value); 1017#else /* DECODE_BUAD */ 1018 cfsetospeed(&termbuf, val); 1019#endif /* DECODE_BUAD */ 1020} 1021 1022 void 1023tty_rspeed(val) 1024 int val; 1025{ 1026#ifdef DECODE_BAUD 1027 register struct termspeeds *tp; 1028 1029 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 1030 ; 1031 if (tp->speed == -1) /* back up to last valid value */ 1032 --tp; 1033 cfsetispeed(&termbuf, tp->value); 1034#else /* DECODE_BAUD */ 1035 cfsetispeed(&termbuf, val); 1036#endif /* DECODE_BAUD */ 1037} 1038 1039#if defined(CRAY2) && defined(UNICOS5) 1040 int 1041tty_isnewmap() 1042{ 1043 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && 1044 !(termbuf.c_oflag & ONLRET)); 1045} 1046#endif 1047 1048#ifdef PARENT_DOES_UTMP 1049# ifndef NEWINIT 1050extern struct utmp wtmp; 1051extern char wtmpf[]; 1052# else /* NEWINIT */ 1053int gotalarm; 1054 1055 /* ARGSUSED */ 1056 void 1057nologinproc(sig) 1058 int sig; 1059{ 1060 gotalarm++; 1061} 1062# endif /* NEWINIT */ 1063#endif /* PARENT_DOES_UTMP */ 1064 1065#ifndef NEWINIT 1066# ifdef PARENT_DOES_UTMP 1067extern void utmp_sig_init P((void)); 1068extern void utmp_sig_reset P((void)); 1069extern void utmp_sig_wait P((void)); 1070extern void utmp_sig_notify P((int)); 1071# endif /* PARENT_DOES_UTMP */ 1072#endif 1073 1074/* 1075 * getptyslave() 1076 * 1077 * Open the slave side of the pty, and do any initialization 1078 * that is necessary. The return value is a file descriptor 1079 * for the slave side. 1080 */ 1081 void 1082getptyslave() 1083{ 1084 register int t = -1; 1085 char erase; 1086 1087#if !defined(CRAY) || !defined(NEWINIT) 1088# ifdef LINEMODE 1089 int waslm; 1090# endif 1091# ifdef TIOCGWINSZ 1092 struct winsize ws; 1093 extern int def_row, def_col; 1094# endif 1095 extern int def_tspeed, def_rspeed; 1096 /* 1097 * Opening the slave side may cause initilization of the 1098 * kernel tty structure. We need remember the state of 1099 * if linemode was turned on 1100 * terminal window size 1101 * terminal speed 1102 * erase character 1103 * so that we can re-set them if we need to. 1104 */ 1105# ifdef LINEMODE 1106 waslm = tty_linemode(); 1107# endif 1108 erase = termbuf.c_cc[VERASE]; 1109 1110 /* 1111 * Make sure that we don't have a controlling tty, and 1112 * that we are the session (process group) leader. 1113 */ 1114# ifdef TIOCNOTTY 1115 t = open(_PATH_TTY, O_RDWR); 1116 if (t >= 0) { 1117 (void) ioctl(t, TIOCNOTTY, (char *)0); 1118 (void) close(t); 1119 } 1120# endif 1121 1122 1123# ifdef PARENT_DOES_UTMP 1124 /* 1125 * Wait for our parent to get the utmp stuff to get done. 1126 */ 1127 utmp_sig_wait(); 1128# endif 1129 1130 t = cleanopen(line); 1131 if (t < 0) 1132 fatalperror(net, line); 1133 1134#ifdef STREAMSPTY 1135#ifdef USE_TERMIO 1136 ttyfd = t; 1137#endif 1138 if (ioctl(t, I_PUSH, "ptem") < 0) 1139 fatal(net, "I_PUSH ptem"); 1140 if (ioctl(t, I_PUSH, "ldterm") < 0) 1141 fatal(net, "I_PUSH ldterm"); 1142 if (ioctl(t, I_PUSH, "ttcompat") < 0) 1143 fatal(net, "I_PUSH ttcompat"); 1144 if (ioctl(pty, I_PUSH, "pckt") < 0) 1145 fatal(net, "I_PUSH pckt"); 1146#endif 1147 1148 /* 1149 * set up the tty modes as we like them to be. 1150 */ 1151 init_termbuf(); 1152# ifdef TIOCGWINSZ 1153 if (def_row || def_col) { 1154 memset((char *)&ws, 0, sizeof(ws)); 1155 ws.ws_col = def_col; 1156 ws.ws_row = def_row; 1157 (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 1158 } 1159# endif 1160 1161 /* 1162 * Settings for sgtty based systems 1163 */ 1164# ifndef USE_TERMIO 1165 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 1166# endif /* USE_TERMIO */ 1167 1168 /* 1169 * Settings for UNICOS (and HPUX) 1170 */ 1171# if defined(CRAY) || defined(__hpux) 1172 termbuf.c_oflag = OPOST|ONLCR|TAB3; 1173 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 1174 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 1175 termbuf.c_cflag = EXTB|HUPCL|CS8; 1176# endif 1177 1178 /* 1179 * Settings for all other termios/termio based 1180 * systems, other than 4.4BSD. In 4.4BSD the 1181 * kernel does the initial terminal setup. 1182 */ 1183# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) 1184# ifndef OXTABS 1185# define OXTABS 0 1186# endif 1187 termbuf.c_lflag |= ECHO; 1188 termbuf.c_oflag |= ONLCR|OXTABS; 1189 termbuf.c_iflag |= ICRNL; 1190 termbuf.c_iflag &= ~IXOFF; 1191# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */ 1192 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 1193 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 1194 if (erase) 1195 termbuf.c_cc[VERASE] = erase; 1196# ifdef LINEMODE 1197 if (waslm) 1198 tty_setlinemode(1); 1199# endif /* LINEMODE */ 1200 1201 /* 1202 * Set the tty modes, and make this our controlling tty. 1203 */ 1204 set_termbuf(); 1205 if (login_tty(t) == -1) 1206 fatalperror(net, "login_tty"); 1207#endif /* !defined(CRAY) || !defined(NEWINIT) */ 1208 if (net > 2) 1209 (void) close(net); 1210#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1211 /* 1212 * Leave the pty open so that we can write out the rlogin 1213 * protocol for /bin/login, if the authentication works. 1214 */ 1215#else 1216 if (pty > 2) { 1217 (void) close(pty); 1218 pty = -1; 1219 } 1220#endif 1221} 1222 1223#if !defined(CRAY) || !defined(NEWINIT) 1224#ifndef O_NOCTTY 1225#define O_NOCTTY 0 1226#endif 1227/* 1228 * Open the specified slave side of the pty, 1229 * making sure that we have a clean tty. 1230 */ 1231 int 1232cleanopen(line) 1233 char *line; 1234{ 1235 register int t; 1236#ifdef UNICOS7x 1237 struct secstat secbuf; 1238#endif /* UNICOS7x */ 1239 1240#ifndef STREAMSPTY 1241 /* 1242 * Make sure that other people can't open the 1243 * slave side of the connection. 1244 */ 1245 (void) chown(line, 0, 0); 1246 (void) chmod(line, 0600); 1247#endif 1248 1249# if !defined(CRAY) && (BSD > 43) 1250 (void) revoke(line); 1251# endif 1252#ifdef UNICOS7x 1253 if (secflag) { 1254 if (secstat(line, &secbuf) < 0) 1255 return(-1); 1256 if (setulvl(secbuf.st_slevel) < 0) 1257 return(-1); 1258 if (setucmp(secbuf.st_compart) < 0) 1259 return(-1); 1260 } 1261#endif /* UNICOS7x */ 1262 1263 t = open(line, O_RDWR|O_NOCTTY); 1264 1265#ifdef UNICOS7x 1266 if (secflag) { 1267 if (setulvl(sysv.sy_minlvl) < 0) 1268 return(-1); 1269 if (setucmp(0) < 0) 1270 return(-1); 1271 } 1272#endif /* UNICOS7x */ 1273 1274 if (t < 0) 1275 return(-1); 1276 1277 /* 1278 * Hangup anybody else using this ttyp, then reopen it for 1279 * ourselves. 1280 */ 1281# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) 1282 (void) signal(SIGHUP, SIG_IGN); 1283 vhangup(); 1284 (void) signal(SIGHUP, SIG_DFL); 1285 t = open(line, O_RDWR|O_NOCTTY); 1286 if (t < 0) 1287 return(-1); 1288# endif 1289# if defined(CRAY) && defined(TCVHUP) 1290 { 1291 register int i; 1292 (void) signal(SIGHUP, SIG_IGN); 1293 (void) ioctl(t, TCVHUP, (char *)0); 1294 (void) signal(SIGHUP, SIG_DFL); 1295 1296#ifdef UNICOS7x 1297 if (secflag) { 1298 if (secstat(line, &secbuf) < 0) 1299 return(-1); 1300 if (setulvl(secbuf.st_slevel) < 0) 1301 return(-1); 1302 if (setucmp(secbuf.st_compart) < 0) 1303 return(-1); 1304 } 1305#endif /* UNICOS7x */ 1306 1307 i = open(line, O_RDWR); 1308 1309#ifdef UNICOS7x 1310 if (secflag) { 1311 if (setulvl(sysv.sy_minlvl) < 0) 1312 return(-1); 1313 if (setucmp(0) < 0) 1314 return(-1); 1315 } 1316#endif /* UNICOS7x */ 1317 1318 if (i < 0) 1319 return(-1); 1320 (void) close(t); 1321 t = i; 1322 } 1323# endif /* defined(CRAY) && defined(TCVHUP) */ 1324 return(t); 1325} 1326#endif /* !defined(CRAY) || !defined(NEWINIT) */ 1327 1328#if BSD <= 43 1329 1330 int 1331login_tty(t) 1332 int t; 1333{ 1334 if (setsid() < 0) { 1335#ifdef ultrix 1336 /* 1337 * The setsid() may have failed because we 1338 * already have a pgrp == pid. Zero out 1339 * our pgrp and try again... 1340 */ 1341 if ((setpgrp(0, 0) < 0) || (setsid() < 0)) 1342#endif 1343 fatalperror(net, "setsid()"); 1344 } 1345# ifdef TIOCSCTTY 1346 if (ioctl(t, TIOCSCTTY, (char *)0) < 0) 1347 fatalperror(net, "ioctl(sctty)"); 1348# if defined(CRAY) 1349 /* 1350 * Close the hard fd to /dev/ttypXXX, and re-open through 1351 * the indirect /dev/tty interface. 1352 */ 1353 close(t); 1354 if ((t = open("/dev/tty", O_RDWR)) < 0) 1355 fatalperror(net, "open(/dev/tty)"); 1356# endif 1357# else 1358 /* 1359 * We get our controlling tty assigned as a side-effect 1360 * of opening up a tty device. But on BSD based systems, 1361 * this only happens if our process group is zero. The 1362 * setsid() call above may have set our pgrp, so clear 1363 * it out before opening the tty... 1364 */ 1365# ifndef SOLARIS 1366 (void) setpgrp(0, 0); 1367# else 1368 (void) setpgrp(); 1369# endif 1370 close(open(line, O_RDWR)); 1371# endif 1372 if (t != 0) 1373 (void) dup2(t, 0); 1374 if (t != 1) 1375 (void) dup2(t, 1); 1376 if (t != 2) 1377 (void) dup2(t, 2); 1378 if (t > 2) 1379 close(t); 1380 return(0); 1381} 1382#endif /* BSD <= 43 */ 1383 1384#ifdef NEWINIT 1385char *gen_id = "fe"; 1386#endif 1387 1388/* 1389 * startslave(host) 1390 * 1391 * Given a hostname, do whatever 1392 * is necessary to startup the login process on the slave side of the pty. 1393 */ 1394 1395/* ARGSUSED */ 1396 void 1397startslave(host, autologin, autoname) 1398 char *host; 1399 int autologin; 1400 char *autoname; 1401{ 1402 register int i; 1403 long time(); 1404#ifdef NEWINIT 1405 extern char *ptyip; 1406 struct init_request request; 1407 void nologinproc(); 1408 register int n; 1409#endif /* NEWINIT */ 1410 1411#if defined(AUTHENTICATION) 1412 if (!autoname || !autoname[0]) 1413 autologin = 0; 1414 1415 if (autologin < auth_level) { 1416 fatal(net, "Authorization failed"); 1417 exit(1); 1418 } 1419#endif 1420 1421#ifndef NEWINIT 1422# ifdef PARENT_DOES_UTMP 1423 utmp_sig_init(); 1424# endif /* PARENT_DOES_UTMP */ 1425 1426 if ((i = fork()) < 0) 1427 fatalperror(net, "fork"); 1428 if (i) { 1429# ifdef PARENT_DOES_UTMP 1430 /* 1431 * Cray parent will create utmp entry for child and send 1432 * signal to child to tell when done. Child waits for signal 1433 * before doing anything important. 1434 */ 1435 register int pid = i; 1436 void sigjob P((int)); 1437 1438 setpgrp(); 1439 utmp_sig_reset(); /* reset handler to default */ 1440 /* 1441 * Create utmp entry for child 1442 */ 1443 (void) time(&wtmp.ut_time); 1444 wtmp.ut_type = LOGIN_PROCESS; 1445 wtmp.ut_pid = pid; 1446 SCPYN(wtmp.ut_user, "LOGIN"); 1447 SCPYN(wtmp.ut_host, host); 1448 SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); 1449#ifndef __hpux 1450 SCPYN(wtmp.ut_id, wtmp.ut_line+3); 1451#else 1452 SCPYN(wtmp.ut_id, wtmp.ut_line+7); 1453#endif 1454 pututline(&wtmp); 1455 endutent(); 1456 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 1457 (void) write(i, (char *)&wtmp, sizeof(struct utmp)); 1458 (void) close(i); 1459 } 1460#ifdef CRAY 1461 (void) signal(WJSIGNAL, sigjob); 1462#endif 1463 utmp_sig_notify(pid); 1464# endif /* PARENT_DOES_UTMP */ 1465 } else { 1466 getptyslave(autologin); 1467 start_login(host, autologin, autoname); 1468 /*NOTREACHED*/ 1469 } 1470#else /* NEWINIT */ 1471 1472 /* 1473 * Init will start up login process if we ask nicely. We only wait 1474 * for it to start up and begin normal telnet operation. 1475 */ 1476 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { 1477 char tbuf[128]; 1478 (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); 1479 fatalperror(net, tbuf); 1480 } 1481 memset((char *)&request, 0, sizeof(request)); 1482 request.magic = INIT_MAGIC; 1483 SCPYN(request.gen_id, gen_id); 1484 SCPYN(request.tty_id, &line[8]); 1485 SCPYN(request.host, host); 1486 SCPYN(request.term_type, terminaltype ? terminaltype : "network"); 1487#if !defined(UNICOS5) 1488 request.signal = SIGCLD; 1489 request.pid = getpid(); 1490#endif 1491#ifdef BFTPDAEMON 1492 /* 1493 * Are we working as the bftp daemon? 1494 */ 1495 if (bftpd) { 1496 SCPYN(request.exec_name, BFTPPATH); 1497 } 1498#endif /* BFTPDAEMON */ 1499 if (write(i, (char *)&request, sizeof(request)) < 0) { 1500 char tbuf[128]; 1501 (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); 1502 fatalperror(net, tbuf); 1503 } 1504 (void) close(i); 1505 (void) signal(SIGALRM, nologinproc); 1506 for (i = 0; ; i++) { 1507 char tbuf[128]; 1508 alarm(15); 1509 n = read(pty, ptyip, BUFSIZ); 1510 if (i == 3 || n >= 0 || !gotalarm) 1511 break; 1512 gotalarm = 0; 1513 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); 1514 (void) write(net, tbuf, strlen(tbuf)); 1515 } 1516 if (n < 0 && gotalarm) 1517 fatal(net, "/etc/init didn't start login process"); 1518 pcc += n; 1519 alarm(0); 1520 (void) signal(SIGALRM, SIG_DFL); 1521 1522 return; 1523#endif /* NEWINIT */ 1524} 1525 1526char *envinit[3]; 1527extern char **environ; 1528 1529 void 1530init_env() 1531{ 1532 extern char *getenv(); 1533 char **envp; 1534 1535 envp = envinit; 1536 if ((*envp = getenv("TZ"))) 1537 *envp++ -= 3; 1538#if defined(CRAY) || defined(__hpux) 1539 else 1540 *envp++ = "TZ=GMT0"; 1541#endif 1542 *envp = 0; 1543 environ = envinit; 1544} 1545 1546#ifndef NEWINIT 1547 1548/* 1549 * start_login(host) 1550 * 1551 * Assuming that we are now running as a child processes, this 1552 * function will turn us into the login process. 1553 */ 1554 1555 void 1556start_login(host, autologin, name) 1557 char *host; 1558 int autologin; 1559 char *name; 1560{ 1561 register char **argv; 1562 char **addarg(), *user; 1563 extern char *getenv(); 1564#ifdef UTMPX 1565 register int pid = getpid(); 1566 struct utmpx utmpx; 1567#endif 1568#ifdef SOLARIS 1569 char *term; 1570 char termbuf[64]; 1571#endif 1572 1573#ifdef UTMPX 1574 /* 1575 * Create utmp entry for child 1576 */ 1577 1578 memset(&utmpx, 0, sizeof(utmpx)); 1579 SCPYN(utmpx.ut_user, ".telnet"); 1580 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); 1581 utmpx.ut_pid = pid; 1582 utmpx.ut_id[0] = 't'; 1583 utmpx.ut_id[1] = 'n'; 1584 utmpx.ut_id[2] = SC_WILDC; 1585 utmpx.ut_id[3] = SC_WILDC; 1586 utmpx.ut_type = LOGIN_PROCESS; 1587 (void) time(&utmpx.ut_tv.tv_sec); 1588 if (makeutx(&utmpx) == NULL) 1589 fatal(net, "makeutx failed"); 1590#endif 1591 1592 scrub_env(); 1593 1594 /* 1595 * -h : pass on name of host. 1596 * WARNING: -h is accepted by login if and only if 1597 * getuid() == 0. 1598 * -p : don't clobber the environment (so terminal type stays set). 1599 * 1600 * -f : force this login, he has already been authenticated 1601 */ 1602 argv = addarg(0, "login"); 1603 1604#if !defined(NO_LOGIN_H) 1605 1606# if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1607 /* 1608 * Don't add the "-h host" option if we are going 1609 * to be adding the "-r host" option down below... 1610 */ 1611 if ((auth_level < 0) || (autologin != AUTH_VALID)) 1612# endif 1613 { 1614 argv = addarg(argv, "-h"); 1615 argv = addarg(argv, host); 1616#ifdef SOLARIS 1617 /* 1618 * SVR4 version of -h takes TERM= as second arg, or - 1619 */ 1620 term = getenv("TERM"); 1621 if (term == NULL || term[0] == 0) { 1622 term = "-"; 1623 } else { 1624 strcpy(termbuf, "TERM="); 1625 strncat(termbuf, term, sizeof(termbuf) - 6); 1626 term = termbuf; 1627 } 1628 argv = addarg(argv, term); 1629#endif 1630 } 1631#endif 1632#if !defined(NO_LOGIN_P) 1633 argv = addarg(argv, "-p"); 1634#endif 1635#ifdef LINEMODE 1636 /* 1637 * Set the environment variable "LINEMODE" to either 1638 * "real" or "kludge" if we are operating in either 1639 * real or kludge linemode. 1640 */ 1641 if (lmodetype == REAL_LINEMODE) 1642 setenv("LINEMODE", "real", 1); 1643# ifdef KLUDGELINEMODE 1644 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 1645 setenv("LINEMODE", "kludge", 1); 1646# endif 1647#endif 1648#ifdef BFTPDAEMON 1649 /* 1650 * Are we working as the bftp daemon? If so, then ask login 1651 * to start bftp instead of shell. 1652 */ 1653 if (bftpd) { 1654 argv = addarg(argv, "-e"); 1655 argv = addarg(argv, BFTPPATH); 1656 } else 1657#endif 1658#if defined (SecurID) 1659 /* 1660 * don't worry about the -f that might get sent. 1661 * A -s is supposed to override it anyhow. 1662 */ 1663 if (require_SecurID) 1664 argv = addarg(argv, "-s"); 1665#endif 1666#if defined (AUTHENTICATION) 1667 if (auth_level >= 0 && autologin == AUTH_VALID) { 1668# if !defined(NO_LOGIN_F) 1669 argv = addarg(argv, "-f"); 1670 argv = addarg(argv, "--"); 1671 argv = addarg(argv, name); 1672# else 1673# if defined(LOGIN_R) 1674 /* 1675 * We don't have support for "login -f", but we 1676 * can fool /bin/login into thinking that we are 1677 * rlogind, and allow us to log in without a 1678 * password. The rlogin protocol expects 1679 * local-user\0remote-user\0term/speed\0 1680 */ 1681 1682 if (pty > 2) { 1683 register char *cp; 1684 char speed[128]; 1685 int isecho, israw, xpty, len; 1686 extern int def_rspeed; 1687# ifndef LOGIN_HOST 1688 /* 1689 * Tell login that we are coming from "localhost". 1690 * If we passed in the real host name, then the 1691 * user would have to allow .rhost access from 1692 * every machine that they want authenticated 1693 * access to work from, which sort of defeats 1694 * the purpose of an authenticated login... 1695 * So, we tell login that the session is coming 1696 * from "localhost", and the user will only have 1697 * to have "localhost" in their .rhost file. 1698 */ 1699# define LOGIN_HOST "localhost" 1700# endif 1701 argv = addarg(argv, "-r"); 1702 argv = addarg(argv, LOGIN_HOST); 1703 1704 xpty = pty; 1705# ifndef STREAMSPTY 1706 pty = 0; 1707# else 1708 ttyfd = 0; 1709# endif 1710 init_termbuf(); 1711 isecho = tty_isecho(); 1712 israw = tty_israw(); 1713 if (isecho || !israw) { 1714 tty_setecho(0); /* Turn off echo */ 1715 tty_setraw(1); /* Turn on raw */ 1716 set_termbuf(); 1717 } 1718 len = strlen(name)+1; 1719 write(xpty, name, len); 1720 write(xpty, name, len); 1721 sprintf(speed, "%s/%d", (cp = getenv("TERM")) ? cp : "", 1722 (def_rspeed > 0) ? def_rspeed : 9600); 1723 len = strlen(speed)+1; 1724 write(xpty, speed, len); 1725 1726 if (isecho || !israw) { 1727 init_termbuf(); 1728 tty_setecho(isecho); 1729 tty_setraw(israw); 1730 set_termbuf(); 1731 if (!israw) { 1732 /* 1733 * Write a newline to ensure 1734 * that login will be able to 1735 * read the line... 1736 */ 1737 write(xpty, "\n", 1); 1738 } 1739 } 1740 pty = xpty; 1741 } 1742# else 1743 argv = addarg(argv, "--"); 1744 argv = addarg(argv, name); 1745# endif 1746# endif 1747 } else 1748#endif 1749 if (getenv("USER")) { 1750 argv = addarg(argv, "--"); 1751 argv = addarg(argv, getenv("USER")); 1752#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) 1753 { 1754 register char **cpp; 1755 for (cpp = environ; *cpp; cpp++) 1756 argv = addarg(argv, *cpp); 1757 } 1758#endif 1759 /* 1760 * Assume that login will set the USER variable 1761 * correctly. For SysV systems, this means that 1762 * USER will no longer be set, just LOGNAME by 1763 * login. (The problem is that if the auto-login 1764 * fails, and the user then specifies a different 1765 * account name, he can get logged in with both 1766 * LOGNAME and USER in his environment, but the 1767 * USER value will be wrong. 1768 */ 1769 unsetenv("USER"); 1770 } 1771#ifdef SOLARIS 1772 else { 1773 char **p; 1774 1775 argv = addarg(argv, ""); /* no login name */ 1776 for (p = environ; *p; p++) { 1777 argv = addarg(argv, *p); 1778 } 1779 } 1780#endif /* SOLARIS */ 1781#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1782 if (pty > 2) 1783 close(pty); 1784#endif 1785 closelog(); 1786 1787 if (altlogin == NULL) { 1788 altlogin = _PATH_LOGIN; 1789 } 1790 execv(altlogin, argv); 1791 1792 syslog(LOG_ERR, "%s: %m\n", altlogin); 1793 fatalperror(net, altlogin); 1794 /*NOTREACHED*/ 1795} 1796 1797 char ** 1798addarg(argv, val) 1799 register char **argv; 1800 register char *val; 1801{ 1802 register char **cpp; 1803 1804 if (argv == NULL) { 1805 /* 1806 * 10 entries, a leading length, and a null 1807 */ 1808 argv = (char **)malloc(sizeof(*argv) * 12); 1809 if (argv == NULL) 1810 return(NULL); 1811 *argv++ = (char *)10; 1812 *argv = (char *)0; 1813 } 1814 for (cpp = argv; *cpp; cpp++) 1815 ; 1816 if (cpp == &argv[(int)argv[-1]]) { 1817 --argv; 1818 *argv = (char *)((int)(*argv) + 10); 1819 argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2)); 1820 if (argv == NULL) 1821 return(NULL); 1822 argv++; 1823 cpp = &argv[(int)argv[-1] - 10]; 1824 } 1825 *cpp++ = val; 1826 *cpp = 0; 1827 return(argv); 1828} 1829#endif /* NEWINIT */ 1830 1831/* 1832 * scrub_env() 1833 * 1834 * Remove a few things from the environment that 1835 * don't need to be there. 1836 */ 1837 void 1838scrub_env() 1839{ 1840 register char **cpp, **cpp2; 1841 1842 for (cpp2 = cpp = environ; *cpp; cpp++) { 1843#ifdef __FreeBSD__ 1844 if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) && 1845 strncmp(*cpp, "LD_PRELOAD=", 11) && 1846#else 1847 if (strncmp(*cpp, "LD_", 3) && 1848 strncmp(*cpp, "_RLD_", 5) && 1849 strncmp(*cpp, "LIBPATH=", 8) && 1850#endif 1851 strncmp(*cpp, "IFS=", 4)) 1852 *cpp2++ = *cpp; 1853 } 1854 *cpp2 = 0; 1855} 1856 1857/* 1858 * cleanup() 1859 * 1860 * This is the routine to call when we are all through, to 1861 * clean up anything that needs to be cleaned up. 1862 */ 1863 /* ARGSUSED */ 1864 void 1865cleanup(sig) 1866 int sig; 1867{ 1868#ifndef PARENT_DOES_UTMP 1869# if (BSD > 43) || defined(convex) 1870 char *p; 1871 1872 p = line + sizeof("/dev/") - 1; 1873 if (logout(p)) 1874 logwtmp(p, "", ""); 1875 (void)chmod(line, 0666); 1876 (void)chown(line, 0, 0); 1877 *p = 'p'; 1878 (void)chmod(line, 0666); 1879 (void)chown(line, 0, 0); 1880 (void) shutdown(net, 2); 1881 exit(1); 1882# else 1883 void rmut(); 1884 1885 rmut(); 1886 vhangup(); /* XXX */ 1887 (void) shutdown(net, 2); 1888 exit(1); 1889# endif 1890#else /* PARENT_DOES_UTMP */ 1891# ifdef NEWINIT 1892 (void) shutdown(net, 2); 1893 exit(1); 1894# else /* NEWINIT */ 1895# ifdef CRAY 1896 static int incleanup = 0; 1897 register int t; 1898 int child_status; /* status of child process as returned by waitpid */ 1899 int flags = WNOHANG|WUNTRACED; 1900 1901 /* 1902 * 1: Pick up the zombie, if we are being called 1903 * as the signal handler. 1904 * 2: If we are a nested cleanup(), return. 1905 * 3: Try to clean up TMPDIR. 1906 * 4: Fill in utmp with shutdown of process. 1907 * 5: Close down the network and pty connections. 1908 * 6: Finish up the TMPDIR cleanup, if needed. 1909 */ 1910 if (sig == SIGCHLD) { 1911 while (waitpid(-1, &child_status, flags) > 0) 1912 ; /* VOID */ 1913 /* Check if the child process was stopped 1914 * rather than exited. We want cleanup only if 1915 * the child has died. 1916 */ 1917 if (WIFSTOPPED(child_status)) { 1918 return; 1919 } 1920 } 1921 t = sigblock(sigmask(SIGCHLD)); 1922 if (incleanup) { 1923 sigsetmask(t); 1924 return; 1925 } 1926 incleanup = 1; 1927 sigsetmask(t); 1928#ifdef UNICOS7x 1929 if (secflag) { 1930 /* 1931 * We need to set ourselves back to a null 1932 * label to clean up. 1933 */ 1934 1935 setulvl(sysv.sy_minlvl); 1936 setucmp((long)0); 1937 } 1938#endif /* UNICOS7x */ 1939 1940 t = cleantmp(&wtmp); 1941 setutent(); /* just to make sure */ 1942# endif /* CRAY */ 1943 rmut(line); 1944 close(pty); 1945 (void) shutdown(net, 2); 1946# ifdef CRAY 1947 if (t == 0) 1948 cleantmp(&wtmp); 1949# endif /* CRAY */ 1950 exit(1); 1951# endif /* NEWINT */ 1952#endif /* PARENT_DOES_UTMP */ 1953} 1954 1955#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT) 1956/* 1957 * _utmp_sig_rcv 1958 * utmp_sig_init 1959 * utmp_sig_wait 1960 * These three functions are used to coordinate the handling of 1961 * the utmp file between the server and the soon-to-be-login shell. 1962 * The server actually creates the utmp structure, the child calls 1963 * utmp_sig_wait(), until the server calls utmp_sig_notify() and 1964 * signals the future-login shell to proceed. 1965 */ 1966static int caught=0; /* NZ when signal intercepted */ 1967static void (*func)(); /* address of previous handler */ 1968 1969 void 1970_utmp_sig_rcv(sig) 1971 int sig; 1972{ 1973 caught = 1; 1974 (void) signal(SIGUSR1, func); 1975} 1976 1977 void 1978utmp_sig_init() 1979{ 1980 /* 1981 * register signal handler for UTMP creation 1982 */ 1983 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 1984 fatalperror(net, "telnetd/signal"); 1985} 1986 1987 void 1988utmp_sig_reset() 1989{ 1990 (void) signal(SIGUSR1, func); /* reset handler to default */ 1991} 1992 1993# ifdef __hpux 1994# define sigoff() /* do nothing */ 1995# define sigon() /* do nothing */ 1996# endif 1997 1998 void 1999utmp_sig_wait() 2000{ 2001 /* 2002 * Wait for parent to write our utmp entry. 2003 */ 2004 sigoff(); 2005 while (caught == 0) { 2006 pause(); /* wait until we get a signal (sigon) */ 2007 sigoff(); /* turn off signals while we check caught */ 2008 } 2009 sigon(); /* turn on signals again */ 2010} 2011 2012 void 2013utmp_sig_notify(pid) 2014{ 2015 kill(pid, SIGUSR1); 2016} 2017 2018# ifdef CRAY 2019static int gotsigjob = 0; 2020 2021 /*ARGSUSED*/ 2022 void 2023sigjob(sig) 2024 int sig; 2025{ 2026 register int jid; 2027 register struct jobtemp *jp; 2028 2029 while ((jid = waitjob(NULL)) != -1) { 2030 if (jid == 0) { 2031 return; 2032 } 2033 gotsigjob++; 2034 jobend(jid, NULL, NULL); 2035 } 2036} 2037 2038/* 2039 * jid_getutid: 2040 * called by jobend() before calling cleantmp() 2041 * to find the correct $TMPDIR to cleanup. 2042 */ 2043 2044 struct utmp * 2045jid_getutid(jid) 2046 int jid; 2047{ 2048 struct utmp *cur = NULL; 2049 2050 setutent(); /* just to make sure */ 2051 while (cur = getutent()) { 2052 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { 2053 return(cur); 2054 } 2055 } 2056 2057 return(0); 2058} 2059 2060/* 2061 * Clean up the TMPDIR that login created. 2062 * The first time this is called we pick up the info 2063 * from the utmp. If the job has already gone away, 2064 * then we'll clean up and be done. If not, then 2065 * when this is called the second time it will wait 2066 * for the signal that the job is done. 2067 */ 2068 int 2069cleantmp(wtp) 2070 register struct utmp *wtp; 2071{ 2072 struct utmp *utp; 2073 static int first = 1; 2074 register int mask, omask, ret; 2075 extern struct utmp *getutid P((const struct utmp *_Id)); 2076 2077 2078 mask = sigmask(WJSIGNAL); 2079 2080 if (first == 0) { 2081 omask = sigblock(mask); 2082 while (gotsigjob == 0) 2083 sigpause(omask); 2084 return(1); 2085 } 2086 first = 0; 2087 setutent(); /* just to make sure */ 2088 2089 utp = getutid(wtp); 2090 if (utp == 0) { 2091 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 2092 return(-1); 2093 } 2094 /* 2095 * Nothing to clean up if the user shell was never started. 2096 */ 2097 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) 2098 return(1); 2099 2100 /* 2101 * Block the WJSIGNAL while we are in jobend(). 2102 */ 2103 omask = sigblock(mask); 2104 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); 2105 sigsetmask(omask); 2106 return(ret); 2107} 2108 2109 int 2110jobend(jid, path, user) 2111 register int jid; 2112 register char *path; 2113 register char *user; 2114{ 2115 static int saved_jid = 0; 2116 static int pty_saved_jid = 0; 2117 static char saved_path[sizeof(wtmp.ut_tpath)+1]; 2118 static char saved_user[sizeof(wtmp.ut_user)+1]; 2119 2120 /* 2121 * this little piece of code comes into play 2122 * only when ptyreconnect is used to reconnect 2123 * to an previous session. 2124 * 2125 * this is the only time when the 2126 * "saved_jid != jid" code is executed. 2127 */ 2128 2129 if ( saved_jid && saved_jid != jid ) { 2130 if (!path) { /* called from signal handler */ 2131 pty_saved_jid = jid; 2132 } else { 2133 pty_saved_jid = saved_jid; 2134 } 2135 } 2136 2137 if (path) { 2138 strncpy(saved_path, path, sizeof(wtmp.ut_tpath)); 2139 strncpy(saved_user, user, sizeof(wtmp.ut_user)); 2140 saved_path[sizeof(saved_path)] = '\0'; 2141 saved_user[sizeof(saved_user)] = '\0'; 2142 } 2143 if (saved_jid == 0) { 2144 saved_jid = jid; 2145 return(0); 2146 } 2147 2148 /* if the jid has changed, get the correct entry from the utmp file */ 2149 2150 if ( saved_jid != jid ) { 2151 struct utmp *utp = NULL; 2152 struct utmp *jid_getutid(); 2153 2154 utp = jid_getutid(pty_saved_jid); 2155 2156 if (utp == 0) { 2157 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 2158 return(-1); 2159 } 2160 2161 cleantmpdir(jid, utp->ut_tpath, utp->ut_user); 2162 return(1); 2163 } 2164 2165 cleantmpdir(jid, saved_path, saved_user); 2166 return(1); 2167} 2168 2169/* 2170 * Fork a child process to clean up the TMPDIR 2171 */ 2172cleantmpdir(jid, tpath, user) 2173 register int jid; 2174 register char *tpath; 2175 register char *user; 2176{ 2177 switch(fork()) { 2178 case -1: 2179 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", 2180 tpath); 2181 break; 2182 case 0: 2183 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); 2184 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", 2185 tpath, CLEANTMPCMD); 2186 exit(1); 2187 default: 2188 /* 2189 * Forget about child. We will exit, and 2190 * /etc/init will pick it up. 2191 */ 2192 break; 2193 } 2194} 2195# endif /* CRAY */ 2196#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */ 2197 2198/* 2199 * rmut() 2200 * 2201 * This is the function called by cleanup() to 2202 * remove the utmp entry for this person. 2203 */ 2204 2205#ifdef UTMPX 2206 void 2207rmut() 2208{ 2209 register f; 2210 int found = 0; 2211 struct utmp *u, *utmp; 2212 int nutmp; 2213 struct stat statbf; 2214 2215 struct utmpx *utxp, utmpx; 2216 2217 /* 2218 * This updates the utmpx and utmp entries and make a wtmp/x entry 2219 */ 2220 2221 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); 2222 utxp = getutxline(&utmpx); 2223 if (utxp) { 2224 utxp->ut_type = DEAD_PROCESS; 2225 utxp->ut_exit.e_termination = 0; 2226 utxp->ut_exit.e_exit = 0; 2227 (void) time(&utmpx.ut_tv.tv_sec); 2228 utmpx.ut_tv.tv_usec = 0; 2229 modutx(utxp); 2230 } 2231 endutxent(); 2232} /* end of rmut */ 2233#endif 2234 2235#if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43 2236 void 2237rmut() 2238{ 2239 register f; 2240 int found = 0; 2241 struct utmp *u, *utmp; 2242 int nutmp; 2243 struct stat statbf; 2244 2245 f = open(utmpf, O_RDWR); 2246 if (f >= 0) { 2247 (void) fstat(f, &statbf); 2248 utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 2249 if (!utmp) 2250 syslog(LOG_ERR, "utmp malloc failed"); 2251 if (statbf.st_size && utmp) { 2252 nutmp = read(f, (char *)utmp, (int)statbf.st_size); 2253 nutmp /= sizeof(struct utmp); 2254 2255 for (u = utmp ; u < &utmp[nutmp] ; u++) { 2256 if (SCMPN(u->ut_line, line+5) || 2257 u->ut_name[0]==0) 2258 continue; 2259 (void) lseek(f, ((long)u)-((long)utmp), L_SET); 2260 SCPYN(u->ut_name, ""); 2261 SCPYN(u->ut_host, ""); 2262 (void) time(&u->ut_time); 2263 (void) write(f, (char *)u, sizeof(wtmp)); 2264 found++; 2265 } 2266 } 2267 (void) close(f); 2268 } 2269 if (found) { 2270 f = open(wtmpf, O_WRONLY|O_APPEND); 2271 if (f >= 0) { 2272 SCPYN(wtmp.ut_line, line+5); 2273 SCPYN(wtmp.ut_name, ""); 2274 SCPYN(wtmp.ut_host, ""); 2275 (void) time(&wtmp.ut_time); 2276 (void) write(f, (char *)&wtmp, sizeof(wtmp)); 2277 (void) close(f); 2278 } 2279 } 2280 (void) chmod(line, 0666); 2281 (void) chown(line, 0, 0); 2282 line[strlen("/dev/")] = 'p'; 2283 (void) chmod(line, 0666); 2284 (void) chown(line, 0, 0); 2285} /* end of rmut */ 2286#endif /* CRAY */ 2287 2288#ifdef __hpux 2289rmut (line) 2290char *line; 2291{ 2292 struct utmp utmp; 2293 struct utmp *utptr; 2294 int fd; /* for /etc/wtmp */ 2295 2296 utmp.ut_type = USER_PROCESS; 2297 (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id)); 2298 (void) setutent(); 2299 utptr = getutid(&utmp); 2300 /* write it out only if it exists */ 2301 if (utptr) { 2302 utptr->ut_type = DEAD_PROCESS; 2303 utptr->ut_time = time((long *) 0); 2304 (void) pututline(utptr); 2305 /* set wtmp entry if wtmp file exists */ 2306 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { 2307 (void) write(fd, utptr, sizeof(utmp)); 2308 (void) close(fd); 2309 } 2310 } 2311 (void) endutent(); 2312 2313 (void) chmod(line, 0666); 2314 (void) chown(line, 0, 0); 2315 line[14] = line[13]; 2316 line[13] = line[12]; 2317 line[8] = 'm'; 2318 line[9] = '/'; 2319 line[10] = 'p'; 2320 line[11] = 't'; 2321 line[12] = 'y'; 2322 (void) chmod(line, 0666); 2323 (void) chown(line, 0, 0); 2324} 2325#endif 2326