1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 33 #endif 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/types.h> 39 //#include <sys/tty.h> 40 #include <libutil.h> 41 #include <stdlib.h> 42 43 #include "telnetd.h" 44 #include "pathnames.h" 45 #include "types.h" 46 #include "baud.h" 47 48 #ifdef AUTHENTICATION 49 #include <libtelnet/auth.h> 50 #endif 51 52 int cleanopen(char *); 53 void scrub_env(void); 54 55 char *envinit[3]; 56 extern char **environ; 57 58 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 59 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 60 61 #ifdef t_erase 62 #undef t_erase 63 #undef t_kill 64 #undef t_intrc 65 #undef t_quitc 66 #undef t_startc 67 #undef t_stopc 68 #undef t_eofc 69 #undef t_brkc 70 #undef t_suspc 71 #undef t_dsuspc 72 #undef t_rprntc 73 #undef t_flushc 74 #undef t_werasc 75 #undef t_lnextc 76 #endif 77 78 #ifndef USE_TERMIO 79 struct termbuf { 80 struct sgttyb sg; 81 struct tchars tc; 82 struct ltchars ltc; 83 int state; 84 int lflags; 85 } termbuf, termbuf2; 86 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) 87 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) 88 # define cfgetospeed(tp) (tp)->sg.sg_ospeed 89 # define cfgetispeed(tp) (tp)->sg.sg_ispeed 90 #else /* USE_TERMIO */ 91 # ifndef TCSANOW 92 # ifdef TCSETS 93 # define TCSANOW TCSETS 94 # define TCSADRAIN TCSETSW 95 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 96 # else 97 # ifdef TCSETA 98 # define TCSANOW TCSETA 99 # define TCSADRAIN TCSETAW 100 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 101 # else 102 # define TCSANOW TIOCSETA 103 # define TCSADRAIN TIOCSETAW 104 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 105 # endif 106 # endif 107 # define tcsetattr(f, a, t) ioctl(f, a, t) 108 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 109 (tp)->c_cflag |= (val) 110 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) 111 # ifdef CIBAUD 112 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 113 (tp)->c_cflag |= ((val)<<IBSHIFT) 114 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) 115 # else 116 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 117 (tp)->c_cflag |= (val) 118 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) 119 # endif 120 # endif /* TCSANOW */ 121 struct termios termbuf, termbuf2; /* pty control structure */ 122 #endif /* USE_TERMIO */ 123 124 #include <sys/types.h> 125 #include <libutil.h> 126 127 int cleanopen(char *); 128 void scrub_env(void); 129 static char **addarg(char **, const char *); 130 131 /* 132 * init_termbuf() 133 * copy_termbuf(cp) 134 * set_termbuf() 135 * 136 * These three routines are used to get and set the "termbuf" structure 137 * to and from the kernel. init_termbuf() gets the current settings. 138 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 139 * set_termbuf() writes the structure into the kernel. 140 */ 141 142 void 143 init_termbuf(void) 144 { 145 #ifndef USE_TERMIO 146 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); 147 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); 148 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); 149 # ifdef TIOCGSTATE 150 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); 151 # endif 152 #else 153 (void) tcgetattr(pty, &termbuf); 154 #endif 155 termbuf2 = termbuf; 156 } 157 158 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 159 void 160 copy_termbuf(char *cp, size_t len) 161 { 162 if (len > sizeof(termbuf)) 163 len = sizeof(termbuf); 164 memmove((char *)&termbuf, cp, len); 165 termbuf2 = termbuf; 166 } 167 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 168 169 void 170 set_termbuf(void) 171 { 172 /* 173 * Only make the necessary changes. 174 */ 175 #ifndef USE_TERMIO 176 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, 177 sizeof(termbuf.sg))) 178 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); 179 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, 180 sizeof(termbuf.tc))) 181 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); 182 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, 183 sizeof(termbuf.ltc))) 184 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); 185 if (termbuf.lflags != termbuf2.lflags) 186 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); 187 #else /* USE_TERMIO */ 188 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 189 (void) tcsetattr(pty, TCSANOW, &termbuf); 190 #endif /* USE_TERMIO */ 191 } 192 193 194 /* 195 * spcset(func, valp, valpp) 196 * 197 * This function takes various special characters (func), and 198 * sets *valp to the current value of that character, and 199 * *valpp to point to where in the "termbuf" structure that 200 * value is kept. 201 * 202 * It returns the SLC_ level of support for this function. 203 */ 204 205 #ifndef USE_TERMIO 206 int 207 spcset(int func, cc_t *valp, cc_t **valpp) 208 { 209 switch(func) { 210 case SLC_EOF: 211 *valp = termbuf.tc.t_eofc; 212 *valpp = (cc_t *)&termbuf.tc.t_eofc; 213 return(SLC_VARIABLE); 214 case SLC_EC: 215 *valp = termbuf.sg.sg_erase; 216 *valpp = (cc_t *)&termbuf.sg.sg_erase; 217 return(SLC_VARIABLE); 218 case SLC_EL: 219 *valp = termbuf.sg.sg_kill; 220 *valpp = (cc_t *)&termbuf.sg.sg_kill; 221 return(SLC_VARIABLE); 222 case SLC_IP: 223 *valp = termbuf.tc.t_intrc; 224 *valpp = (cc_t *)&termbuf.tc.t_intrc; 225 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 226 case SLC_ABORT: 227 *valp = termbuf.tc.t_quitc; 228 *valpp = (cc_t *)&termbuf.tc.t_quitc; 229 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 230 case SLC_XON: 231 *valp = termbuf.tc.t_startc; 232 *valpp = (cc_t *)&termbuf.tc.t_startc; 233 return(SLC_VARIABLE); 234 case SLC_XOFF: 235 *valp = termbuf.tc.t_stopc; 236 *valpp = (cc_t *)&termbuf.tc.t_stopc; 237 return(SLC_VARIABLE); 238 case SLC_AO: 239 *valp = termbuf.ltc.t_flushc; 240 *valpp = (cc_t *)&termbuf.ltc.t_flushc; 241 return(SLC_VARIABLE); 242 case SLC_SUSP: 243 *valp = termbuf.ltc.t_suspc; 244 *valpp = (cc_t *)&termbuf.ltc.t_suspc; 245 return(SLC_VARIABLE); 246 case SLC_EW: 247 *valp = termbuf.ltc.t_werasc; 248 *valpp = (cc_t *)&termbuf.ltc.t_werasc; 249 return(SLC_VARIABLE); 250 case SLC_RP: 251 *valp = termbuf.ltc.t_rprntc; 252 *valpp = (cc_t *)&termbuf.ltc.t_rprntc; 253 return(SLC_VARIABLE); 254 case SLC_LNEXT: 255 *valp = termbuf.ltc.t_lnextc; 256 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 257 return(SLC_VARIABLE); 258 case SLC_FORW1: 259 *valp = termbuf.tc.t_brkc; 260 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 261 return(SLC_VARIABLE); 262 case SLC_BRK: 263 case SLC_SYNCH: 264 case SLC_AYT: 265 case SLC_EOR: 266 *valp = (cc_t)0; 267 *valpp = (cc_t *)0; 268 return(SLC_DEFAULT); 269 default: 270 *valp = (cc_t)0; 271 *valpp = (cc_t *)0; 272 return(SLC_NOSUPPORT); 273 } 274 } 275 276 #else /* USE_TERMIO */ 277 278 279 #define setval(a, b) *valp = termbuf.c_cc[a]; \ 280 *valpp = &termbuf.c_cc[a]; \ 281 return(b); 282 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 283 284 int 285 spcset(int func, cc_t *valp, cc_t **valpp) 286 { 287 switch(func) { 288 case SLC_EOF: 289 setval(VEOF, SLC_VARIABLE); 290 case SLC_EC: 291 setval(VERASE, SLC_VARIABLE); 292 case SLC_EL: 293 setval(VKILL, SLC_VARIABLE); 294 case SLC_IP: 295 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 296 case SLC_ABORT: 297 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 298 case SLC_XON: 299 #ifdef VSTART 300 setval(VSTART, SLC_VARIABLE); 301 #else 302 defval(0x13); 303 #endif 304 case SLC_XOFF: 305 #ifdef VSTOP 306 setval(VSTOP, SLC_VARIABLE); 307 #else 308 defval(0x11); 309 #endif 310 case SLC_EW: 311 #ifdef VWERASE 312 setval(VWERASE, SLC_VARIABLE); 313 #else 314 defval(0); 315 #endif 316 case SLC_RP: 317 #ifdef VREPRINT 318 setval(VREPRINT, SLC_VARIABLE); 319 #else 320 defval(0); 321 #endif 322 case SLC_LNEXT: 323 #ifdef VLNEXT 324 setval(VLNEXT, SLC_VARIABLE); 325 #else 326 defval(0); 327 #endif 328 case SLC_AO: 329 #if !defined(VDISCARD) && defined(VFLUSHO) 330 # define VDISCARD VFLUSHO 331 #endif 332 #ifdef VDISCARD 333 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 334 #else 335 defval(0); 336 #endif 337 case SLC_SUSP: 338 #ifdef VSUSP 339 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 340 #else 341 defval(0); 342 #endif 343 #ifdef VEOL 344 case SLC_FORW1: 345 setval(VEOL, SLC_VARIABLE); 346 #endif 347 #ifdef VEOL2 348 case SLC_FORW2: 349 setval(VEOL2, SLC_VARIABLE); 350 #endif 351 case SLC_AYT: 352 #ifdef VSTATUS 353 setval(VSTATUS, SLC_VARIABLE); 354 #else 355 defval(0); 356 #endif 357 358 case SLC_BRK: 359 case SLC_SYNCH: 360 case SLC_EOR: 361 defval(0); 362 363 default: 364 *valp = 0; 365 *valpp = 0; 366 return(SLC_NOSUPPORT); 367 } 368 } 369 #endif /* USE_TERMIO */ 370 371 /* 372 * getpty() 373 * 374 * Allocate a pty. As a side effect, the external character 375 * array "line" contains the name of the slave side. 376 * 377 * Returns the file descriptor of the opened pty. 378 */ 379 int 380 getpty(int *ptynum __unused) 381 { 382 int p; 383 const char *pn; 384 385 p = posix_openpt(O_RDWR|O_NOCTTY); 386 if (p < 0) 387 return (-1); 388 389 if (grantpt(p) == -1) 390 return (-1); 391 392 if (unlockpt(p) == -1) 393 return (-1); 394 395 pn = ptsname(p); 396 if (pn == NULL) 397 return (-1); 398 399 if (strlcpy(line, pn, sizeof line) >= sizeof line) 400 return (-1); 401 402 return (p); 403 } 404 405 #ifdef LINEMODE 406 /* 407 * tty_flowmode() Find out if flow control is enabled or disabled. 408 * tty_linemode() Find out if linemode (external processing) is enabled. 409 * tty_setlinemod(on) Turn on/off linemode. 410 * tty_isecho() Find out if echoing is turned on. 411 * tty_setecho(on) Enable/disable character echoing. 412 * tty_israw() Find out if terminal is in RAW mode. 413 * tty_binaryin(on) Turn on/off BINARY on input. 414 * tty_binaryout(on) Turn on/off BINARY on output. 415 * tty_isediting() Find out if line editing is enabled. 416 * tty_istrapsig() Find out if signal trapping is enabled. 417 * tty_setedit(on) Turn on/off line editing. 418 * tty_setsig(on) Turn on/off signal trapping. 419 * tty_issofttab() Find out if tab expansion is enabled. 420 * tty_setsofttab(on) Turn on/off soft tab expansion. 421 * tty_islitecho() Find out if typed control chars are echoed literally 422 * tty_setlitecho() Turn on/off literal echo of control chars 423 * tty_tspeed(val) Set transmit speed to val. 424 * tty_rspeed(val) Set receive speed to val. 425 */ 426 427 428 int 429 tty_linemode(void) 430 { 431 #ifndef USE_TERMIO 432 return(termbuf.state & TS_EXTPROC); 433 #else 434 return(termbuf.c_lflag & EXTPROC); 435 #endif 436 } 437 438 void 439 tty_setlinemode(int on) 440 { 441 #ifdef TIOCEXT 442 set_termbuf(); 443 (void) ioctl(pty, TIOCEXT, (char *)&on); 444 init_termbuf(); 445 #else /* !TIOCEXT */ 446 # ifdef EXTPROC 447 if (on) 448 termbuf.c_lflag |= EXTPROC; 449 else 450 termbuf.c_lflag &= ~EXTPROC; 451 # endif 452 #endif /* TIOCEXT */ 453 } 454 #endif /* LINEMODE */ 455 456 int 457 tty_isecho(void) 458 { 459 #ifndef USE_TERMIO 460 return (termbuf.sg.sg_flags & ECHO); 461 #else 462 return (termbuf.c_lflag & ECHO); 463 #endif 464 } 465 466 int 467 tty_flowmode(void) 468 { 469 #ifndef USE_TERMIO 470 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); 471 #else 472 return((termbuf.c_iflag & IXON) ? 1 : 0); 473 #endif 474 } 475 476 int 477 tty_restartany(void) 478 { 479 #ifndef USE_TERMIO 480 # ifdef DECCTQ 481 return((termbuf.lflags & DECCTQ) ? 0 : 1); 482 # else 483 return(-1); 484 # endif 485 #else 486 return((termbuf.c_iflag & IXANY) ? 1 : 0); 487 #endif 488 } 489 490 void 491 tty_setecho(int on) 492 { 493 #ifndef USE_TERMIO 494 if (on) 495 termbuf.sg.sg_flags |= ECHO|CRMOD; 496 else 497 termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 498 #else 499 if (on) 500 termbuf.c_lflag |= ECHO; 501 else 502 termbuf.c_lflag &= ~ECHO; 503 #endif 504 } 505 506 int 507 tty_israw(void) 508 { 509 #ifndef USE_TERMIO 510 return(termbuf.sg.sg_flags & RAW); 511 #else 512 return(!(termbuf.c_lflag & ICANON)); 513 #endif 514 } 515 516 #ifdef AUTHENTICATION 517 #if defined(NO_LOGIN_F) && defined(LOGIN_R) 518 int 519 tty_setraw(int on) 520 { 521 # ifndef USE_TERMIO 522 if (on) 523 termbuf.sg.sg_flags |= RAW; 524 else 525 termbuf.sg.sg_flags &= ~RAW; 526 # else 527 if (on) 528 termbuf.c_lflag &= ~ICANON; 529 else 530 termbuf.c_lflag |= ICANON; 531 # endif 532 } 533 #endif 534 #endif /* AUTHENTICATION */ 535 536 void 537 tty_binaryin(int on) 538 { 539 #ifndef USE_TERMIO 540 if (on) 541 termbuf.lflags |= LPASS8; 542 else 543 termbuf.lflags &= ~LPASS8; 544 #else 545 if (on) { 546 termbuf.c_iflag &= ~ISTRIP; 547 } else { 548 termbuf.c_iflag |= ISTRIP; 549 } 550 #endif 551 } 552 553 void 554 tty_binaryout(int on) 555 { 556 #ifndef USE_TERMIO 557 if (on) 558 termbuf.lflags |= LLITOUT; 559 else 560 termbuf.lflags &= ~LLITOUT; 561 #else 562 if (on) { 563 termbuf.c_cflag &= ~(CSIZE|PARENB); 564 termbuf.c_cflag |= CS8; 565 termbuf.c_oflag &= ~OPOST; 566 } else { 567 termbuf.c_cflag &= ~CSIZE; 568 termbuf.c_cflag |= CS7|PARENB; 569 termbuf.c_oflag |= OPOST; 570 } 571 #endif 572 } 573 574 int 575 tty_isbinaryin(void) 576 { 577 #ifndef USE_TERMIO 578 return(termbuf.lflags & LPASS8); 579 #else 580 return(!(termbuf.c_iflag & ISTRIP)); 581 #endif 582 } 583 584 int 585 tty_isbinaryout(void) 586 { 587 #ifndef USE_TERMIO 588 return(termbuf.lflags & LLITOUT); 589 #else 590 return(!(termbuf.c_oflag&OPOST)); 591 #endif 592 } 593 594 #ifdef LINEMODE 595 int 596 tty_isediting(void) 597 { 598 #ifndef USE_TERMIO 599 return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 600 #else 601 return(termbuf.c_lflag & ICANON); 602 #endif 603 } 604 605 int 606 tty_istrapsig(void) 607 { 608 #ifndef USE_TERMIO 609 return(!(termbuf.sg.sg_flags&RAW)); 610 #else 611 return(termbuf.c_lflag & ISIG); 612 #endif 613 } 614 615 void 616 tty_setedit(int on) 617 { 618 #ifndef USE_TERMIO 619 if (on) 620 termbuf.sg.sg_flags &= ~CBREAK; 621 else 622 termbuf.sg.sg_flags |= CBREAK; 623 #else 624 if (on) 625 termbuf.c_lflag |= ICANON; 626 else 627 termbuf.c_lflag &= ~ICANON; 628 #endif 629 } 630 631 void 632 tty_setsig(int on) 633 { 634 #ifndef USE_TERMIO 635 if (on) 636 ; 637 #else 638 if (on) 639 termbuf.c_lflag |= ISIG; 640 else 641 termbuf.c_lflag &= ~ISIG; 642 #endif 643 } 644 #endif /* LINEMODE */ 645 646 int 647 tty_issofttab(void) 648 { 649 #ifndef USE_TERMIO 650 return (termbuf.sg.sg_flags & XTABS); 651 #else 652 # ifdef OXTABS 653 return (termbuf.c_oflag & OXTABS); 654 # endif 655 # ifdef TABDLY 656 return ((termbuf.c_oflag & TABDLY) == TAB3); 657 # endif 658 #endif 659 } 660 661 void 662 tty_setsofttab(int on) 663 { 664 #ifndef USE_TERMIO 665 if (on) 666 termbuf.sg.sg_flags |= XTABS; 667 else 668 termbuf.sg.sg_flags &= ~XTABS; 669 #else 670 if (on) { 671 # ifdef OXTABS 672 termbuf.c_oflag |= OXTABS; 673 # endif 674 # ifdef TABDLY 675 termbuf.c_oflag &= ~TABDLY; 676 termbuf.c_oflag |= TAB3; 677 # endif 678 } else { 679 # ifdef OXTABS 680 termbuf.c_oflag &= ~OXTABS; 681 # endif 682 # ifdef TABDLY 683 termbuf.c_oflag &= ~TABDLY; 684 termbuf.c_oflag |= TAB0; 685 # endif 686 } 687 #endif 688 } 689 690 int 691 tty_islitecho(void) 692 { 693 #ifndef USE_TERMIO 694 return (!(termbuf.lflags & LCTLECH)); 695 #else 696 # ifdef ECHOCTL 697 return (!(termbuf.c_lflag & ECHOCTL)); 698 # endif 699 # ifdef TCTLECH 700 return (!(termbuf.c_lflag & TCTLECH)); 701 # endif 702 # if !defined(ECHOCTL) && !defined(TCTLECH) 703 return (0); /* assumes ctl chars are echoed '^x' */ 704 # endif 705 #endif 706 } 707 708 void 709 tty_setlitecho(int on) 710 { 711 #ifndef USE_TERMIO 712 if (on) 713 termbuf.lflags &= ~LCTLECH; 714 else 715 termbuf.lflags |= LCTLECH; 716 #else 717 # ifdef ECHOCTL 718 if (on) 719 termbuf.c_lflag &= ~ECHOCTL; 720 else 721 termbuf.c_lflag |= ECHOCTL; 722 # endif 723 # ifdef TCTLECH 724 if (on) 725 termbuf.c_lflag &= ~TCTLECH; 726 else 727 termbuf.c_lflag |= TCTLECH; 728 # endif 729 #endif 730 } 731 732 int 733 tty_iscrnl(void) 734 { 735 #ifndef USE_TERMIO 736 return (termbuf.sg.sg_flags & CRMOD); 737 #else 738 return (termbuf.c_iflag & ICRNL); 739 #endif 740 } 741 742 void 743 tty_tspeed(int val) 744 { 745 #ifdef DECODE_BAUD 746 struct termspeeds *tp; 747 748 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 749 ; 750 if (tp->speed == -1) /* back up to last valid value */ 751 --tp; 752 cfsetospeed(&termbuf, tp->value); 753 #else /* DECODE_BAUD */ 754 cfsetospeed(&termbuf, val); 755 #endif /* DECODE_BAUD */ 756 } 757 758 void 759 tty_rspeed(int val) 760 { 761 #ifdef DECODE_BAUD 762 struct termspeeds *tp; 763 764 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 765 ; 766 if (tp->speed == -1) /* back up to last valid value */ 767 --tp; 768 cfsetispeed(&termbuf, tp->value); 769 #else /* DECODE_BAUD */ 770 cfsetispeed(&termbuf, val); 771 #endif /* DECODE_BAUD */ 772 } 773 774 /* 775 * getptyslave() 776 * 777 * Open the slave side of the pty, and do any initialization 778 * that is necessary. 779 */ 780 static void 781 getptyslave(void) 782 { 783 int t = -1; 784 char erase; 785 786 # ifdef LINEMODE 787 int waslm; 788 # endif 789 # ifdef TIOCGWINSZ 790 struct winsize ws; 791 extern int def_row, def_col; 792 # endif 793 extern int def_tspeed, def_rspeed; 794 /* 795 * Opening the slave side may cause initilization of the 796 * kernel tty structure. We need remember the state of 797 * if linemode was turned on 798 * terminal window size 799 * terminal speed 800 * erase character 801 * so that we can re-set them if we need to. 802 */ 803 # ifdef LINEMODE 804 waslm = tty_linemode(); 805 # endif 806 erase = termbuf.c_cc[VERASE]; 807 808 /* 809 * Make sure that we don't have a controlling tty, and 810 * that we are the session (process group) leader. 811 */ 812 # ifdef TIOCNOTTY 813 t = open(_PATH_TTY, O_RDWR); 814 if (t >= 0) { 815 (void) ioctl(t, TIOCNOTTY, (char *)0); 816 (void) close(t); 817 } 818 # endif 819 820 t = cleanopen(line); 821 if (t < 0) 822 fatalperror(net, line); 823 824 825 /* 826 * set up the tty modes as we like them to be. 827 */ 828 init_termbuf(); 829 # ifdef TIOCGWINSZ 830 if (def_row || def_col) { 831 memset((char *)&ws, 0, sizeof(ws)); 832 ws.ws_col = def_col; 833 ws.ws_row = def_row; 834 (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 835 } 836 # endif 837 838 /* 839 * Settings for sgtty based systems 840 */ 841 # ifndef USE_TERMIO 842 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 843 # endif /* USE_TERMIO */ 844 845 /* 846 * Settings for all other termios/termio based 847 * systems, other than 4.4BSD. In 4.4BSD the 848 * kernel does the initial terminal setup. 849 */ 850 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 851 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 852 if (erase) 853 termbuf.c_cc[VERASE] = erase; 854 # ifdef LINEMODE 855 if (waslm) 856 tty_setlinemode(1); 857 # endif /* LINEMODE */ 858 859 /* 860 * Set the tty modes, and make this our controlling tty. 861 */ 862 set_termbuf(); 863 if (login_tty(t) == -1) 864 fatalperror(net, "login_tty"); 865 if (net > 2) 866 (void) close(net); 867 #ifdef AUTHENTICATION 868 #if defined(NO_LOGIN_F) && defined(LOGIN_R) 869 /* 870 * Leave the pty open so that we can write out the rlogin 871 * protocol for /bin/login, if the authentication works. 872 */ 873 #else 874 if (pty > 2) { 875 (void) close(pty); 876 pty = -1; 877 } 878 #endif 879 #endif /* AUTHENTICATION */ 880 } 881 882 #ifndef O_NOCTTY 883 #define O_NOCTTY 0 884 #endif 885 /* 886 * Open the specified slave side of the pty, 887 * making sure that we have a clean tty. 888 */ 889 int 890 cleanopen(char *li) 891 { 892 int t; 893 894 /* 895 * Make sure that other people can't open the 896 * slave side of the connection. 897 */ 898 (void) chown(li, 0, 0); 899 (void) chmod(li, 0600); 900 901 #if (!defined(__BEOS__) && !defined(__HAIKU__)) 902 (void) revoke(li); 903 #endif 904 905 t = open(line, O_RDWR|O_NOCTTY); 906 907 if (t < 0) 908 return(-1); 909 910 return(t); 911 } 912 913 /* 914 * startslave(host) 915 * 916 * Given a hostname, do whatever 917 * is necessary to startup the login process on the slave side of the pty. 918 */ 919 920 /* ARGSUSED */ 921 void 922 startslave(char *host, int autologin, char *autoname) 923 { 924 int i; 925 926 #ifdef AUTHENTICATION 927 if (!autoname || !autoname[0]) 928 autologin = 0; 929 930 if (autologin < auth_level) { 931 fatal(net, "Authorization failed"); 932 exit(1); 933 } 934 #endif 935 936 937 if ((i = fork()) < 0) 938 fatalperror(net, "fork"); 939 if (i) { 940 } else { 941 getptyslave(); 942 start_login(host, autologin, autoname); 943 /*NOTREACHED*/ 944 } 945 } 946 947 void 948 init_env(void) 949 { 950 char **envp; 951 952 envp = envinit; 953 if ((*envp = getenv("TZ"))) 954 *envp++ -= 3; 955 *envp = 0; 956 environ = envinit; 957 } 958 959 960 /* 961 * start_login(host) 962 * 963 * Assuming that we are now running as a child processes, this 964 * function will turn us into the login process. 965 */ 966 967 #ifndef AUTHENTICATION 968 #define undef1 __unused 969 #else 970 #define undef1 971 #endif 972 973 void 974 start_login(char *host undef1, int autologin undef1, char *name undef1) 975 { 976 char **argv; 977 char *user; 978 979 user = getenv("USER"); 980 user = (user != NULL) ? strdup(user) : NULL; 981 982 scrub_env(); 983 984 /* 985 * -h : pass on name of host. 986 * WARNING: -h is accepted by login if and only if 987 * getuid() == 0. 988 * -p : don't clobber the environment (so terminal type stays set). 989 * 990 * -f : force this login, he has already been authenticated 991 */ 992 argv = addarg(0, "login"); 993 994 #if !defined(NO_LOGIN_H) 995 #ifdef AUTHENTICATION 996 # if defined(NO_LOGIN_F) && defined(LOGIN_R) 997 /* 998 * Don't add the "-h host" option if we are going 999 * to be adding the "-r host" option down below... 1000 */ 1001 if ((auth_level < 0) || (autologin != AUTH_VALID)) 1002 # endif 1003 #endif /* AUTHENTICATION */ 1004 { 1005 argv = addarg(argv, "-h"); 1006 argv = addarg(argv, host); 1007 } 1008 #endif 1009 #if !defined(NO_LOGIN_P) 1010 argv = addarg(argv, "-p"); 1011 #endif 1012 #ifdef LINEMODE 1013 /* 1014 * Set the environment variable "LINEMODE" to either 1015 * "real" or "kludge" if we are operating in either 1016 * real or kludge linemode. 1017 */ 1018 if (lmodetype == REAL_LINEMODE) 1019 setenv("LINEMODE", "real", 1); 1020 # ifdef KLUDGELINEMODE 1021 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 1022 setenv("LINEMODE", "kludge", 1); 1023 # endif 1024 #endif 1025 #ifdef BFTPDAEMON 1026 /* 1027 * Are we working as the bftp daemon? If so, then ask login 1028 * to start bftp instead of shell. 1029 */ 1030 if (bftpd) { 1031 argv = addarg(argv, "-e"); 1032 argv = addarg(argv, BFTPPATH); 1033 } else 1034 #endif 1035 #ifdef AUTHENTICATION 1036 if (auth_level >= 0 && autologin == AUTH_VALID) { 1037 # if !defined(NO_LOGIN_F) 1038 argv = addarg(argv, "-f"); 1039 argv = addarg(argv, "--"); 1040 argv = addarg(argv, name); 1041 # else 1042 # if defined(LOGIN_R) 1043 /* 1044 * We don't have support for "login -f", but we 1045 * can fool /bin/login into thinking that we are 1046 * rlogind, and allow us to log in without a 1047 * password. The rlogin protocol expects 1048 * local-user\0remote-user\0term/speed\0 1049 */ 1050 1051 if (pty > 2) { 1052 char *cp; 1053 char speed[128]; 1054 int isecho, israw, xpty, len; 1055 extern int def_rspeed; 1056 # ifndef LOGIN_HOST 1057 /* 1058 * Tell login that we are coming from "localhost". 1059 * If we passed in the real host name, then the 1060 * user would have to allow .rhost access from 1061 * every machine that they want authenticated 1062 * access to work from, which sort of defeats 1063 * the purpose of an authenticated login... 1064 * So, we tell login that the session is coming 1065 * from "localhost", and the user will only have 1066 * to have "localhost" in their .rhost file. 1067 */ 1068 # define LOGIN_HOST "localhost" 1069 # endif 1070 argv = addarg(argv, "-r"); 1071 argv = addarg(argv, LOGIN_HOST); 1072 1073 xpty = pty; 1074 pty = 0; 1075 init_termbuf(); 1076 isecho = tty_isecho(); 1077 israw = tty_israw(); 1078 if (isecho || !israw) { 1079 tty_setecho(0); /* Turn off echo */ 1080 tty_setraw(1); /* Turn on raw */ 1081 set_termbuf(); 1082 } 1083 len = strlen(name)+1; 1084 write(xpty, name, len); 1085 write(xpty, name, len); 1086 snprintf(speed, sizeof(speed), 1087 "%s/%d", (cp = getenv("TERM")) ? cp : "", 1088 (def_rspeed > 0) ? def_rspeed : 9600); 1089 len = strlen(speed)+1; 1090 write(xpty, speed, len); 1091 1092 if (isecho || !israw) { 1093 init_termbuf(); 1094 tty_setecho(isecho); 1095 tty_setraw(israw); 1096 set_termbuf(); 1097 if (!israw) { 1098 /* 1099 * Write a newline to ensure 1100 * that login will be able to 1101 * read the line... 1102 */ 1103 write(xpty, "\n", 1); 1104 } 1105 } 1106 pty = xpty; 1107 } 1108 # else 1109 argv = addarg(argv, "--"); 1110 argv = addarg(argv, name); 1111 # endif 1112 # endif 1113 } else 1114 #endif 1115 if (user != NULL) { 1116 argv = addarg(argv, "--"); 1117 argv = addarg(argv, user); 1118 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) 1119 { 1120 char **cpp; 1121 for (cpp = environ; *cpp; cpp++) 1122 argv = addarg(argv, *cpp); 1123 } 1124 #endif 1125 } 1126 #ifdef AUTHENTICATION 1127 #if defined(NO_LOGIN_F) && defined(LOGIN_R) 1128 if (pty > 2) 1129 close(pty); 1130 #endif 1131 #endif /* AUTHENTICATION */ 1132 closelog(); 1133 1134 if (user != NULL) 1135 free(user); 1136 1137 if (altlogin == NULL) { 1138 altlogin = _PATH_LOGIN; 1139 } 1140 execv(altlogin, argv); 1141 1142 syslog(LOG_ERR, "%s: %m", altlogin); 1143 fatalperror(net, altlogin); 1144 /*NOTREACHED*/ 1145 } 1146 1147 static char ** 1148 addarg(char **argv, const char *val) 1149 { 1150 char **cpp; 1151 1152 if (argv == NULL) { 1153 /* 1154 * 10 entries, a leading length, and a null 1155 */ 1156 argv = (char **)malloc(sizeof(*argv) * 12); 1157 if (argv == NULL) 1158 fatal(net, "failure allocating argument space"); 1159 *argv++ = (char *)10; 1160 *argv = (char *)0; 1161 } 1162 for (cpp = argv; *cpp; cpp++) 1163 ; 1164 if (cpp == &argv[(long)argv[-1]]) { 1165 --argv; 1166 *argv = (char *)((long)(*argv) + 10); 1167 argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2)); 1168 if (argv == NULL) 1169 fatal(net, "failure allocating argument space"); 1170 argv++; 1171 cpp = &argv[(long)argv[-1] - 10]; 1172 } 1173 if ((*cpp++ = strdup(val)) == NULL) 1174 fatal(net, "failure allocating argument space"); 1175 *cpp = 0; 1176 return(argv); 1177 } 1178 1179 /* 1180 * scrub_env() 1181 * 1182 * We only accept the environment variables listed below. 1183 */ 1184 void 1185 scrub_env(void) 1186 { 1187 static const char *rej[] = { 1188 "TERMCAP=/", 1189 NULL 1190 }; 1191 1192 static const char *acc[] = { 1193 "XAUTH=", "XAUTHORITY=", "DISPLAY=", 1194 "TERM=", 1195 "EDITOR=", 1196 "PAGER=", 1197 "LOGNAME=", 1198 "POSIXLY_CORRECT=", 1199 "PRINTER=", 1200 NULL 1201 }; 1202 1203 char **cpp, **cpp2; 1204 const char **p; 1205 char ** new_environ; 1206 size_t count; 1207 1208 /* Allocate space for scrubbed environment. */ 1209 for (count = 1, cpp = environ; *cpp; count++, cpp++) 1210 continue; 1211 if ((new_environ = malloc(count * sizeof(char *))) == NULL) { 1212 environ = NULL; 1213 return; 1214 } 1215 1216 for (cpp2 = new_environ, cpp = environ; *cpp; cpp++) { 1217 int reject_it = 0; 1218 1219 for(p = rej; *p; p++) 1220 if(strncmp(*cpp, *p, strlen(*p)) == 0) { 1221 reject_it = 1; 1222 break; 1223 } 1224 if (reject_it) 1225 continue; 1226 1227 for(p = acc; *p; p++) 1228 if(strncmp(*cpp, *p, strlen(*p)) == 0) 1229 break; 1230 if(*p != NULL) { 1231 if ((*cpp2++ = strdup(*cpp)) == NULL) { 1232 environ = new_environ; 1233 return; 1234 } 1235 } 1236 } 1237 *cpp2 = NULL; 1238 environ = new_environ; 1239 } 1240 1241 /* 1242 * cleanup() 1243 * 1244 * This is the routine to call when we are all through, to 1245 * clean up anything that needs to be cleaned up. 1246 */ 1247 /* ARGSUSED */ 1248 void 1249 cleanup(int sig __unused) 1250 { 1251 1252 (void) shutdown(net, SHUT_RDWR); 1253 _exit(1); 1254 } 1255