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