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