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