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