1 /* $NetBSD: sys_term.c,v 1.40 2003/09/19 05:54:46 itojun Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 36 #else 37 __RCSID("$NetBSD: sys_term.c,v 1.40 2003/09/19 05:54:46 itojun Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include "telnetd.h" 42 #include "pathnames.h" 43 44 #include <util.h> 45 46 #include <sys/cdefs.h> 47 48 #include <utmp.h> 49 struct utmp wtmp; 50 51 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 52 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 53 54 struct termios termbuf, termbuf2; /* pty control structure */ 55 56 void getptyslave __P((void)); 57 int cleanopen __P((char *)); 58 char **addarg __P((char **, char *)); 59 void scrub_env __P((void)); 60 int getent __P((char *, char *)); 61 char *getstr __P((const char *, char **)); 62 #ifdef KRB5 63 extern void kerberos5_cleanup __P((void)); 64 #endif 65 66 /* 67 * init_termbuf() 68 * copy_termbuf(cp) 69 * set_termbuf() 70 * 71 * These three routines are used to get and set the "termbuf" structure 72 * to and from the kernel. init_termbuf() gets the current settings. 73 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 74 * set_termbuf() writes the structure into the kernel. 75 */ 76 77 void 78 init_termbuf() 79 { 80 (void) tcgetattr(pty, &termbuf); 81 termbuf2 = termbuf; 82 } 83 84 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 85 void 86 copy_termbuf(cp, len) 87 char *cp; 88 int len; 89 { 90 if (len > sizeof(termbuf)) 91 len = sizeof(termbuf); 92 memmove((char *)&termbuf, cp, len); 93 termbuf2 = termbuf; 94 } 95 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 96 97 void 98 set_termbuf() 99 { 100 /* 101 * Only make the necessary changes. 102 */ 103 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 104 (void) tcsetattr(pty, TCSANOW, &termbuf); 105 } 106 107 108 /* 109 * spcset(func, valp, valpp) 110 * 111 * This function takes various special characters (func), and 112 * sets *valp to the current value of that character, and 113 * *valpp to point to where in the "termbuf" structure that 114 * value is kept. 115 * 116 * It returns the SLC_ level of support for this function. 117 */ 118 119 120 int 121 spcset(func, valp, valpp) 122 int func; 123 cc_t *valp; 124 cc_t **valpp; 125 { 126 127 #define setval(a, b) *valp = termbuf.c_cc[a]; \ 128 *valpp = &termbuf.c_cc[a]; \ 129 return(b); 130 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 131 132 switch(func) { 133 case SLC_EOF: 134 setval(VEOF, SLC_VARIABLE); 135 case SLC_EC: 136 setval(VERASE, SLC_VARIABLE); 137 case SLC_EL: 138 setval(VKILL, SLC_VARIABLE); 139 case SLC_IP: 140 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 141 case SLC_ABORT: 142 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 143 case SLC_XON: 144 setval(VSTART, SLC_VARIABLE); 145 case SLC_XOFF: 146 setval(VSTOP, SLC_VARIABLE); 147 case SLC_EW: 148 setval(VWERASE, SLC_VARIABLE); 149 case SLC_RP: 150 setval(VREPRINT, SLC_VARIABLE); 151 case SLC_LNEXT: 152 setval(VLNEXT, SLC_VARIABLE); 153 case SLC_AO: 154 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 155 case SLC_SUSP: 156 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 157 case SLC_FORW1: 158 setval(VEOL, SLC_VARIABLE); 159 case SLC_FORW2: 160 setval(VEOL2, SLC_VARIABLE); 161 case SLC_AYT: 162 setval(VSTATUS, SLC_VARIABLE); 163 164 case SLC_BRK: 165 case SLC_SYNCH: 166 case SLC_EOR: 167 defval(0); 168 169 default: 170 *valp = 0; 171 *valpp = 0; 172 return(SLC_NOSUPPORT); 173 } 174 } 175 176 177 /* 178 * getpty() 179 * 180 * Allocate a pty. As a side effect, the external character 181 * array "line" contains the name of the slave side. 182 * 183 * Returns the file descriptor of the opened pty. 184 */ 185 #ifndef __GNUC__ 186 char *line = NULL16STR; 187 #else 188 static char Xline[] = NULL16STR; 189 char *line = Xline; 190 #endif 191 192 193 static int ptyslavefd; /* for cleanopen() */ 194 195 int 196 getpty(ptynum) 197 int *ptynum; 198 { 199 int ptyfd; 200 201 ptyfd = openpty(ptynum, &ptyslavefd, line, NULL, NULL); 202 if (ptyfd == 0) 203 return *ptynum; 204 ptyslavefd = -1; 205 return (-1); 206 } 207 208 #ifdef LINEMODE 209 /* 210 * tty_flowmode() Find out if flow control is enabled or disabled. 211 * tty_linemode() Find out if linemode (external processing) is enabled. 212 * tty_setlinemod(on) Turn on/off linemode. 213 * tty_isecho() Find out if echoing is turned on. 214 * tty_setecho(on) Enable/disable character echoing. 215 * tty_israw() Find out if terminal is in RAW mode. 216 * tty_binaryin(on) Turn on/off BINARY on input. 217 * tty_binaryout(on) Turn on/off BINARY on output. 218 * tty_isediting() Find out if line editing is enabled. 219 * tty_istrapsig() Find out if signal trapping is enabled. 220 * tty_setedit(on) Turn on/off line editing. 221 * tty_setsig(on) Turn on/off signal trapping. 222 * tty_issofttab() Find out if tab expansion is enabled. 223 * tty_setsofttab(on) Turn on/off soft tab expansion. 224 * tty_islitecho() Find out if typed control chars are echoed literally 225 * tty_setlitecho() Turn on/off literal echo of control chars 226 * tty_tspeed(val) Set transmit speed to val. 227 * tty_rspeed(val) Set receive speed to val. 228 */ 229 230 231 int 232 tty_linemode() 233 { 234 return(termbuf.c_lflag & EXTPROC); 235 } 236 237 void 238 tty_setlinemode(on) 239 int on; 240 { 241 set_termbuf(); 242 (void) ioctl(pty, TIOCEXT, (char *)&on); 243 init_termbuf(); 244 } 245 #endif /* LINEMODE */ 246 247 int 248 tty_isecho() 249 { 250 return (termbuf.c_lflag & ECHO); 251 } 252 253 int 254 tty_flowmode() 255 { 256 return((termbuf.c_iflag & IXON) ? 1 : 0); 257 } 258 259 int 260 tty_restartany() 261 { 262 return((termbuf.c_iflag & IXANY) ? 1 : 0); 263 } 264 265 void 266 tty_setecho(on) 267 int on; 268 { 269 if (on) 270 termbuf.c_lflag |= ECHO; 271 else 272 termbuf.c_lflag &= ~ECHO; 273 } 274 275 int 276 tty_israw() 277 { 278 return(!(termbuf.c_lflag & ICANON)); 279 } 280 281 void 282 tty_binaryin(on) 283 int on; 284 { 285 if (on) { 286 termbuf.c_iflag &= ~ISTRIP; 287 } else { 288 termbuf.c_iflag |= ISTRIP; 289 } 290 } 291 292 void 293 tty_binaryout(on) 294 int on; 295 { 296 if (on) { 297 termbuf.c_cflag &= ~(CSIZE|PARENB); 298 termbuf.c_cflag |= CS8; 299 termbuf.c_oflag &= ~OPOST; 300 } else { 301 termbuf.c_cflag &= ~CSIZE; 302 termbuf.c_cflag |= CS7|PARENB; 303 termbuf.c_oflag |= OPOST; 304 } 305 } 306 307 int 308 tty_isbinaryin() 309 { 310 return(!(termbuf.c_iflag & ISTRIP)); 311 } 312 313 int 314 tty_isbinaryout() 315 { 316 return(!(termbuf.c_oflag&OPOST)); 317 } 318 319 #ifdef LINEMODE 320 int 321 tty_isediting() 322 { 323 return(termbuf.c_lflag & ICANON); 324 } 325 326 int 327 tty_istrapsig() 328 { 329 return(termbuf.c_lflag & ISIG); 330 } 331 332 void 333 tty_setedit(on) 334 int on; 335 { 336 if (on) 337 termbuf.c_lflag |= ICANON; 338 else 339 termbuf.c_lflag &= ~ICANON; 340 } 341 342 void 343 tty_setsig(on) 344 int on; 345 { 346 if (on) 347 termbuf.c_lflag |= ISIG; 348 else 349 termbuf.c_lflag &= ~ISIG; 350 } 351 #endif /* LINEMODE */ 352 353 int 354 tty_issofttab() 355 { 356 # ifdef OXTABS 357 return (termbuf.c_oflag & OXTABS); 358 # endif 359 # ifdef TABDLY 360 return ((termbuf.c_oflag & TABDLY) == TAB3); 361 # endif 362 } 363 364 void 365 tty_setsofttab(on) 366 int on; 367 { 368 if (on) { 369 # ifdef OXTABS 370 termbuf.c_oflag |= OXTABS; 371 # endif 372 # ifdef TABDLY 373 termbuf.c_oflag &= ~TABDLY; 374 termbuf.c_oflag |= TAB3; 375 # endif 376 } else { 377 # ifdef OXTABS 378 termbuf.c_oflag &= ~OXTABS; 379 # endif 380 # ifdef TABDLY 381 termbuf.c_oflag &= ~TABDLY; 382 termbuf.c_oflag |= TAB0; 383 # endif 384 } 385 } 386 387 int 388 tty_islitecho() 389 { 390 # ifdef ECHOCTL 391 return (!(termbuf.c_lflag & ECHOCTL)); 392 # endif 393 # ifdef TCTLECH 394 return (!(termbuf.c_lflag & TCTLECH)); 395 # endif 396 # if !defined(ECHOCTL) && !defined(TCTLECH) 397 return (0); /* assumes ctl chars are echoed '^x' */ 398 # endif 399 } 400 401 void 402 tty_setlitecho(on) 403 int on; 404 { 405 # ifdef ECHOCTL 406 if (on) 407 termbuf.c_lflag &= ~ECHOCTL; 408 else 409 termbuf.c_lflag |= ECHOCTL; 410 # endif 411 # ifdef TCTLECH 412 if (on) 413 termbuf.c_lflag &= ~TCTLECH; 414 else 415 termbuf.c_lflag |= TCTLECH; 416 # endif 417 } 418 419 int 420 tty_iscrnl() 421 { 422 return (termbuf.c_iflag & ICRNL); 423 } 424 425 void 426 tty_tspeed(val) 427 int val; 428 { 429 cfsetospeed(&termbuf, val); 430 } 431 432 void 433 tty_rspeed(val) 434 int val; 435 { 436 cfsetispeed(&termbuf, val); 437 } 438 439 440 441 442 /* 443 * getptyslave() 444 * 445 * Open the slave side of the pty, and do any initialization 446 * that is necessary. The return value is a file descriptor 447 * for the slave side. 448 */ 449 extern int def_tspeed, def_rspeed; 450 extern int def_row, def_col; 451 452 void 453 getptyslave() 454 { 455 register int t = -1; 456 457 #ifdef LINEMODE 458 int waslm; 459 #endif 460 struct winsize ws; 461 /* 462 * Opening the slave side may cause initilization of the 463 * kernel tty structure. We need remember the state of 464 * if linemode was turned on 465 * terminal window size 466 * terminal speed 467 * so that we can re-set them if we need to. 468 */ 469 #ifdef LINEMODE 470 waslm = tty_linemode(); 471 #endif 472 473 /* 474 * Make sure that we don't have a controlling tty, and 475 * that we are the session (process group) leader. 476 */ 477 t = open(_PATH_TTY, O_RDWR); 478 if (t >= 0) { 479 (void) ioctl(t, TIOCNOTTY, (char *)0); 480 (void) close(t); 481 } 482 483 484 485 t = cleanopen(line); 486 if (t < 0) 487 fatalperror(net, line); 488 489 490 /* 491 * set up the tty modes as we like them to be. 492 */ 493 init_termbuf(); 494 if (def_row || def_col) { 495 memset((char *)&ws, 0, sizeof(ws)); 496 ws.ws_col = def_col; 497 ws.ws_row = def_row; 498 (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 499 } 500 501 /* 502 * Settings for sgtty based systems 503 */ 504 505 /* 506 * Settings for all other termios/termio based 507 * systems, other than 4.4BSD. In 4.4BSD the 508 * kernel does the initial terminal setup. 509 */ 510 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 511 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 512 #ifdef LINEMODE 513 if (waslm) 514 tty_setlinemode(1); 515 #endif /* LINEMODE */ 516 517 /* 518 * Set the tty modes, and make this our controlling tty. 519 */ 520 set_termbuf(); 521 if (login_tty(t) == -1) 522 fatalperror(net, "login_tty"); 523 if (net > 2) 524 (void) close(net); 525 if (pty > 2) { 526 (void) close(pty); 527 pty = -1; 528 } 529 } 530 531 /* 532 * Open the specified slave side of the pty, 533 * making sure that we have a clean tty. 534 */ 535 int 536 cleanopen(ttyline) 537 char *ttyline; 538 { 539 return ptyslavefd; 540 } 541 542 /* 543 * startslave(host) 544 * 545 * Given a hostname, do whatever 546 * is necessary to startup the login process on the slave side of the pty. 547 */ 548 549 /* ARGSUSED */ 550 void 551 startslave(host, autologin, autoname) 552 char *host; 553 int autologin; 554 char *autoname; 555 { 556 register int i; 557 558 #ifdef AUTHENTICATION 559 if (!autoname || !autoname[0]) 560 autologin = 0; 561 562 if (autologin < auth_level) { 563 fatal(net, "Authorization failed"); 564 exit(1); 565 } 566 #endif 567 568 569 if ((i = fork()) < 0) 570 fatalperror(net, "fork"); 571 if (i) { 572 } else { 573 getptyslave(); 574 start_login(host, autologin, autoname); 575 /*NOTREACHED*/ 576 } 577 } 578 579 char *envinit[3]; 580 581 void 582 init_env() 583 { 584 char **envp; 585 586 envp = envinit; 587 if ((*envp = getenv("TZ"))) 588 *envp++ -= 3; 589 *envp = 0; 590 environ = envinit; 591 } 592 593 594 /* 595 * start_login(host) 596 * 597 * Assuming that we are now running as a child processes, this 598 * function will turn us into the login process. 599 */ 600 extern char *gettyname; 601 602 void 603 start_login(host, autologin, name) 604 char *host; 605 int autologin; 606 char *name; 607 { 608 register char **argv; 609 #define TABBUFSIZ 512 610 char defent[TABBUFSIZ]; 611 char defstrs[TABBUFSIZ]; 612 #undef TABBUFSIZ 613 const char *loginprog = NULL; 614 615 616 scrub_env(); 617 618 /* 619 * -h : pass on name of host. 620 * WARNING: -h is accepted by login if and only if 621 * getuid() == 0. 622 * -p : don't clobber the environment (so terminal type stays set). 623 * 624 * -f : force this login, he has already been authenticated 625 */ 626 argv = addarg(0, "login"); 627 628 { 629 argv = addarg(argv, "-h"); 630 argv = addarg(argv, host); 631 } 632 argv = addarg(argv, "-p"); 633 #ifdef LINEMODE 634 /* 635 * Set the environment variable "LINEMODE" to either 636 * "real" or "kludge" if we are operating in either 637 * real or kludge linemode. 638 */ 639 if (lmodetype == REAL_LINEMODE) 640 setenv("LINEMODE", "real", 1); 641 # ifdef KLUDGELINEMODE 642 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 643 setenv("LINEMODE", "kludge", 1); 644 # endif 645 #endif 646 #ifdef SECURELOGIN 647 /* 648 * don't worry about the -f that might get sent. 649 * A -s is supposed to override it anyhow. 650 */ 651 if (require_secure_login) 652 argv = addarg(argv, "-s"); 653 #endif 654 #ifdef AUTHENTICATION 655 if (auth_level >= 0 && autologin == AUTH_VALID) { 656 argv = addarg(argv, "-f"); 657 argv = addarg(argv, "--"); 658 argv = addarg(argv, name); 659 } else 660 #endif 661 if (getenv("USER")) { 662 argv = addarg(argv, "--"); 663 argv = addarg(argv, getenv("USER")); 664 /* 665 * Assume that login will set the USER variable 666 * correctly. For SysV systems, this means that 667 * USER will no longer be set, just LOGNAME by 668 * login. (The problem is that if the auto-login 669 * fails, and the user then specifies a different 670 * account name, he can get logged in with both 671 * LOGNAME and USER in his environment, but the 672 * USER value will be wrong. 673 */ 674 unsetenv("USER"); 675 } 676 if (getent(defent, gettyname) == 1) { 677 char *cp = defstrs; 678 679 loginprog = getstr("lo", &cp); 680 } 681 if (loginprog == NULL) 682 loginprog = _PATH_LOGIN; 683 closelog(); 684 /* 685 * This sleep(1) is in here so that telnetd can 686 * finish up with the tty. There's a race condition 687 * the login banner message gets lost... 688 */ 689 sleep(1); 690 execv(loginprog, argv); 691 692 syslog(LOG_ERR, "%s: %m", loginprog); 693 fatalperror(net, loginprog); 694 /*NOTREACHED*/ 695 } 696 697 char ** 698 addarg(argv, val) 699 register char **argv; 700 register char *val; 701 { 702 register char **cpp; 703 char **nargv; 704 705 if (argv == NULL) { 706 /* 707 * 10 entries, a leading length, and a null 708 */ 709 argv = (char **)malloc(sizeof(*argv) * 12); 710 if (argv == NULL) 711 return(NULL); 712 *argv++ = (char *)10; 713 *argv = (char *)0; 714 } 715 for (cpp = argv; *cpp; cpp++) 716 ; 717 if (cpp == &argv[(long)argv[-1]]) { 718 --argv; 719 nargv = (char **)realloc(argv, 720 sizeof(*argv) * ((long)(*argv) + 10 + 2)); 721 if (argv == NULL) { 722 fatal(net, "not enough memory"); 723 /*NOTREACHED*/ 724 } 725 argv = nargv; 726 *argv = (char *)((long)(*argv) + 10); 727 argv++; 728 cpp = &argv[(long)argv[-1] - 10]; 729 } 730 *cpp++ = val; 731 *cpp = 0; 732 return(argv); 733 } 734 735 /* 736 * scrub_env() 737 * 738 * We only accept the environment variables listed below. 739 */ 740 741 void 742 scrub_env() 743 { 744 static const char *reject[] = { 745 "TERMCAP=/", 746 NULL 747 }; 748 749 static const char *acceptstr[] = { 750 "XAUTH=", "XAUTHORITY=", "DISPLAY=", 751 "TERM=", 752 "EDITOR=", 753 "PAGER=", 754 "LOGNAME=", 755 "POSIXLY_CORRECT=", 756 "TERMCAP=", 757 "PRINTER=", 758 NULL 759 }; 760 761 char **cpp, **cpp2; 762 const char **p; 763 764 for (cpp2 = cpp = environ; *cpp; cpp++) { 765 int reject_it = 0; 766 767 for(p = reject; *p; p++) 768 if(strncmp(*cpp, *p, strlen(*p)) == 0) { 769 reject_it = 1; 770 break; 771 } 772 if (reject_it) 773 continue; 774 775 for(p = acceptstr; *p; p++) 776 if(strncmp(*cpp, *p, strlen(*p)) == 0) 777 break; 778 if(*p != NULL) 779 *cpp2++ = *cpp; 780 } 781 *cpp2 = NULL; 782 } 783 784 /* 785 * cleanup() 786 * 787 * This is the routine to call when we are all through, to 788 * clean up anything that needs to be cleaned up. 789 */ 790 /* ARGSUSED */ 791 void 792 cleanup(sig) 793 int sig; 794 { 795 char *p, c; 796 797 p = line + sizeof("/dev/") - 1; 798 #ifdef SUPPORT_UTMP 799 if (logout(p)) 800 logwtmp(p, "", ""); 801 #endif 802 #ifdef SUPPORT_UTMPX 803 if (logoutx(p, 0, DEAD_PROCESS)) 804 logwtmpx(p, "", "", 0, DEAD_PROCESS); 805 #endif 806 (void)chmod(line, 0666); 807 (void)chown(line, 0, 0); 808 c = *p; *p = 'p'; 809 (void)chmod(line, 0666); 810 (void)chown(line, 0, 0); 811 *p = c; 812 if (ttyaction(line, "telnetd", "root")) 813 syslog(LOG_ERR, "%s: ttyaction failed", line); 814 (void) shutdown(net, 2); 815 exit(1); 816 } 817