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