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