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