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