sys_term.c revision 184938
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#if 0 35#ifndef lint 36static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 37#endif 38#endif 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/contrib/telnet/telnetd/sys_term.c 184938 2008-11-13 20:40:38Z ed $"); 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 line[32]; 396 397int 398getpty(int *ptynum __unused) 399{ 400 int p; 401 const char *pn; 402 403 p = posix_openpt(O_RDWR|O_NOCTTY); 404 if (p < 0) 405 return (-1); 406 407 if (grantpt(p) == -1) 408 return (-1); 409 410 if (unlockpt(p) == -1) 411 return (-1); 412 413 pn = ptsname(p); 414 if (pn == NULL) 415 return (-1); 416 417 if (strlcpy(line, pn, sizeof line) >= sizeof line) 418 return (-1); 419 420 return (p); 421} 422 423#ifdef LINEMODE 424/* 425 * tty_flowmode() Find out if flow control is enabled or disabled. 426 * tty_linemode() Find out if linemode (external processing) is enabled. 427 * tty_setlinemod(on) Turn on/off linemode. 428 * tty_isecho() Find out if echoing is turned on. 429 * tty_setecho(on) Enable/disable character echoing. 430 * tty_israw() Find out if terminal is in RAW mode. 431 * tty_binaryin(on) Turn on/off BINARY on input. 432 * tty_binaryout(on) Turn on/off BINARY on output. 433 * tty_isediting() Find out if line editing is enabled. 434 * tty_istrapsig() Find out if signal trapping is enabled. 435 * tty_setedit(on) Turn on/off line editing. 436 * tty_setsig(on) Turn on/off signal trapping. 437 * tty_issofttab() Find out if tab expansion is enabled. 438 * tty_setsofttab(on) Turn on/off soft tab expansion. 439 * tty_islitecho() Find out if typed control chars are echoed literally 440 * tty_setlitecho() Turn on/off literal echo of control chars 441 * tty_tspeed(val) Set transmit speed to val. 442 * tty_rspeed(val) Set receive speed to val. 443 */ 444 445 446int 447tty_linemode(void) 448{ 449#ifndef USE_TERMIO 450 return(termbuf.state & TS_EXTPROC); 451#else 452 return(termbuf.c_lflag & EXTPROC); 453#endif 454} 455 456void 457tty_setlinemode(int on) 458{ 459#ifdef TIOCEXT 460 set_termbuf(); 461 (void) ioctl(pty, TIOCEXT, (char *)&on); 462 init_termbuf(); 463#else /* !TIOCEXT */ 464# ifdef EXTPROC 465 if (on) 466 termbuf.c_lflag |= EXTPROC; 467 else 468 termbuf.c_lflag &= ~EXTPROC; 469# endif 470#endif /* TIOCEXT */ 471} 472#endif /* LINEMODE */ 473 474int 475tty_isecho(void) 476{ 477#ifndef USE_TERMIO 478 return (termbuf.sg.sg_flags & ECHO); 479#else 480 return (termbuf.c_lflag & ECHO); 481#endif 482} 483 484int 485tty_flowmode(void) 486{ 487#ifndef USE_TERMIO 488 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); 489#else 490 return((termbuf.c_iflag & IXON) ? 1 : 0); 491#endif 492} 493 494int 495tty_restartany(void) 496{ 497#ifndef USE_TERMIO 498# ifdef DECCTQ 499 return((termbuf.lflags & DECCTQ) ? 0 : 1); 500# else 501 return(-1); 502# endif 503#else 504 return((termbuf.c_iflag & IXANY) ? 1 : 0); 505#endif 506} 507 508void 509tty_setecho(int on) 510{ 511#ifndef USE_TERMIO 512 if (on) 513 termbuf.sg.sg_flags |= ECHO|CRMOD; 514 else 515 termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 516#else 517 if (on) 518 termbuf.c_lflag |= ECHO; 519 else 520 termbuf.c_lflag &= ~ECHO; 521#endif 522} 523 524int 525tty_israw(void) 526{ 527#ifndef USE_TERMIO 528 return(termbuf.sg.sg_flags & RAW); 529#else 530 return(!(termbuf.c_lflag & ICANON)); 531#endif 532} 533 534#ifdef AUTHENTICATION 535#if defined(NO_LOGIN_F) && defined(LOGIN_R) 536int 537tty_setraw(int on) 538{ 539# ifndef USE_TERMIO 540 if (on) 541 termbuf.sg.sg_flags |= RAW; 542 else 543 termbuf.sg.sg_flags &= ~RAW; 544# else 545 if (on) 546 termbuf.c_lflag &= ~ICANON; 547 else 548 termbuf.c_lflag |= ICANON; 549# endif 550} 551#endif 552#endif /* AUTHENTICATION */ 553 554void 555tty_binaryin(int on) 556{ 557#ifndef USE_TERMIO 558 if (on) 559 termbuf.lflags |= LPASS8; 560 else 561 termbuf.lflags &= ~LPASS8; 562#else 563 if (on) { 564 termbuf.c_iflag &= ~ISTRIP; 565 } else { 566 termbuf.c_iflag |= ISTRIP; 567 } 568#endif 569} 570 571void 572tty_binaryout(int on) 573{ 574#ifndef USE_TERMIO 575 if (on) 576 termbuf.lflags |= LLITOUT; 577 else 578 termbuf.lflags &= ~LLITOUT; 579#else 580 if (on) { 581 termbuf.c_cflag &= ~(CSIZE|PARENB); 582 termbuf.c_cflag |= CS8; 583 termbuf.c_oflag &= ~OPOST; 584 } else { 585 termbuf.c_cflag &= ~CSIZE; 586 termbuf.c_cflag |= CS7|PARENB; 587 termbuf.c_oflag |= OPOST; 588 } 589#endif 590} 591 592int 593tty_isbinaryin(void) 594{ 595#ifndef USE_TERMIO 596 return(termbuf.lflags & LPASS8); 597#else 598 return(!(termbuf.c_iflag & ISTRIP)); 599#endif 600} 601 602int 603tty_isbinaryout(void) 604{ 605#ifndef USE_TERMIO 606 return(termbuf.lflags & LLITOUT); 607#else 608 return(!(termbuf.c_oflag&OPOST)); 609#endif 610} 611 612#ifdef LINEMODE 613int 614tty_isediting(void) 615{ 616#ifndef USE_TERMIO 617 return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 618#else 619 return(termbuf.c_lflag & ICANON); 620#endif 621} 622 623int 624tty_istrapsig(void) 625{ 626#ifndef USE_TERMIO 627 return(!(termbuf.sg.sg_flags&RAW)); 628#else 629 return(termbuf.c_lflag & ISIG); 630#endif 631} 632 633void 634tty_setedit(int on) 635{ 636#ifndef USE_TERMIO 637 if (on) 638 termbuf.sg.sg_flags &= ~CBREAK; 639 else 640 termbuf.sg.sg_flags |= CBREAK; 641#else 642 if (on) 643 termbuf.c_lflag |= ICANON; 644 else 645 termbuf.c_lflag &= ~ICANON; 646#endif 647} 648 649void 650tty_setsig(int on) 651{ 652#ifndef USE_TERMIO 653 if (on) 654 ; 655#else 656 if (on) 657 termbuf.c_lflag |= ISIG; 658 else 659 termbuf.c_lflag &= ~ISIG; 660#endif 661} 662#endif /* LINEMODE */ 663 664int 665tty_issofttab(void) 666{ 667#ifndef USE_TERMIO 668 return (termbuf.sg.sg_flags & XTABS); 669#else 670# ifdef OXTABS 671 return (termbuf.c_oflag & OXTABS); 672# endif 673# ifdef TABDLY 674 return ((termbuf.c_oflag & TABDLY) == TAB3); 675# endif 676#endif 677} 678 679void 680tty_setsofttab(int on) 681{ 682#ifndef USE_TERMIO 683 if (on) 684 termbuf.sg.sg_flags |= XTABS; 685 else 686 termbuf.sg.sg_flags &= ~XTABS; 687#else 688 if (on) { 689# ifdef OXTABS 690 termbuf.c_oflag |= OXTABS; 691# endif 692# ifdef TABDLY 693 termbuf.c_oflag &= ~TABDLY; 694 termbuf.c_oflag |= TAB3; 695# endif 696 } else { 697# ifdef OXTABS 698 termbuf.c_oflag &= ~OXTABS; 699# endif 700# ifdef TABDLY 701 termbuf.c_oflag &= ~TABDLY; 702 termbuf.c_oflag |= TAB0; 703# endif 704 } 705#endif 706} 707 708int 709tty_islitecho(void) 710{ 711#ifndef USE_TERMIO 712 return (!(termbuf.lflags & LCTLECH)); 713#else 714# ifdef ECHOCTL 715 return (!(termbuf.c_lflag & ECHOCTL)); 716# endif 717# ifdef TCTLECH 718 return (!(termbuf.c_lflag & TCTLECH)); 719# endif 720# if !defined(ECHOCTL) && !defined(TCTLECH) 721 return (0); /* assumes ctl chars are echoed '^x' */ 722# endif 723#endif 724} 725 726void 727tty_setlitecho(int on) 728{ 729#ifndef USE_TERMIO 730 if (on) 731 termbuf.lflags &= ~LCTLECH; 732 else 733 termbuf.lflags |= LCTLECH; 734#else 735# ifdef ECHOCTL 736 if (on) 737 termbuf.c_lflag &= ~ECHOCTL; 738 else 739 termbuf.c_lflag |= ECHOCTL; 740# endif 741# ifdef TCTLECH 742 if (on) 743 termbuf.c_lflag &= ~TCTLECH; 744 else 745 termbuf.c_lflag |= TCTLECH; 746# endif 747#endif 748} 749 750int 751tty_iscrnl(void) 752{ 753#ifndef USE_TERMIO 754 return (termbuf.sg.sg_flags & CRMOD); 755#else 756 return (termbuf.c_iflag & ICRNL); 757#endif 758} 759 760/* 761 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 762 */ 763#if B4800 != 4800 764#define DECODE_BAUD 765#endif 766 767#ifdef DECODE_BAUD 768 769/* 770 * A table of available terminal speeds 771 */ 772struct termspeeds { 773 int speed; 774 int value; 775} termspeeds[] = { 776 { 0, B0 }, { 50, B50 }, { 75, B75 }, 777 { 110, B110 }, { 134, B134 }, { 150, B150 }, 778 { 200, B200 }, { 300, B300 }, { 600, B600 }, 779 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 780 { 4800, B4800 }, 781#ifdef B7200 782 { 7200, B7200 }, 783#endif 784 { 9600, B9600 }, 785#ifdef B14400 786 { 14400, B14400 }, 787#endif 788#ifdef B19200 789 { 19200, B19200 }, 790#endif 791#ifdef B28800 792 { 28800, B28800 }, 793#endif 794#ifdef B38400 795 { 38400, B38400 }, 796#endif 797#ifdef B57600 798 { 57600, B57600 }, 799#endif 800#ifdef B115200 801 { 115200, B115200 }, 802#endif 803#ifdef B230400 804 { 230400, B230400 }, 805#endif 806 { -1, 0 } 807}; 808#endif /* DECODE_BAUD */ 809 810void 811tty_tspeed(int val) 812{ 813#ifdef DECODE_BAUD 814 struct termspeeds *tp; 815 816 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 817 ; 818 if (tp->speed == -1) /* back up to last valid value */ 819 --tp; 820 cfsetospeed(&termbuf, tp->value); 821#else /* DECODE_BAUD */ 822 cfsetospeed(&termbuf, val); 823#endif /* DECODE_BAUD */ 824} 825 826void 827tty_rspeed(int val) 828{ 829#ifdef DECODE_BAUD 830 struct termspeeds *tp; 831 832 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 833 ; 834 if (tp->speed == -1) /* back up to last valid value */ 835 --tp; 836 cfsetispeed(&termbuf, tp->value); 837#else /* DECODE_BAUD */ 838 cfsetispeed(&termbuf, val); 839#endif /* DECODE_BAUD */ 840} 841 842/* 843 * getptyslave() 844 * 845 * Open the slave side of the pty, and do any initialization 846 * that is necessary. 847 */ 848static void 849getptyslave(void) 850{ 851 int t = -1; 852 char erase; 853 854# ifdef LINEMODE 855 int waslm; 856# endif 857# ifdef TIOCGWINSZ 858 struct winsize ws; 859 extern int def_row, def_col; 860# endif 861 extern int def_tspeed, def_rspeed; 862 /* 863 * Opening the slave side may cause initilization of the 864 * kernel tty structure. We need remember the state of 865 * if linemode was turned on 866 * terminal window size 867 * terminal speed 868 * erase character 869 * so that we can re-set them if we need to. 870 */ 871# ifdef LINEMODE 872 waslm = tty_linemode(); 873# endif 874 erase = termbuf.c_cc[VERASE]; 875 876 /* 877 * Make sure that we don't have a controlling tty, and 878 * that we are the session (process group) leader. 879 */ 880# ifdef TIOCNOTTY 881 t = open(_PATH_TTY, O_RDWR); 882 if (t >= 0) { 883 (void) ioctl(t, TIOCNOTTY, (char *)0); 884 (void) close(t); 885 } 886# endif 887 888 t = cleanopen(line); 889 if (t < 0) 890 fatalperror(net, line); 891 892 893 /* 894 * set up the tty modes as we like them to be. 895 */ 896 init_termbuf(); 897# ifdef TIOCGWINSZ 898 if (def_row || def_col) { 899 memset((char *)&ws, 0, sizeof(ws)); 900 ws.ws_col = def_col; 901 ws.ws_row = def_row; 902 (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 903 } 904# endif 905 906 /* 907 * Settings for sgtty based systems 908 */ 909# ifndef USE_TERMIO 910 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 911# endif /* USE_TERMIO */ 912 913 /* 914 * Settings for all other termios/termio based 915 * systems, other than 4.4BSD. In 4.4BSD the 916 * kernel does the initial terminal setup. 917 */ 918 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 919 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 920 if (erase) 921 termbuf.c_cc[VERASE] = erase; 922# ifdef LINEMODE 923 if (waslm) 924 tty_setlinemode(1); 925# endif /* LINEMODE */ 926 927 /* 928 * Set the tty modes, and make this our controlling tty. 929 */ 930 set_termbuf(); 931 if (login_tty(t) == -1) 932 fatalperror(net, "login_tty"); 933 if (net > 2) 934 (void) close(net); 935#ifdef AUTHENTICATION 936#if defined(NO_LOGIN_F) && defined(LOGIN_R) 937 /* 938 * Leave the pty open so that we can write out the rlogin 939 * protocol for /bin/login, if the authentication works. 940 */ 941#else 942 if (pty > 2) { 943 (void) close(pty); 944 pty = -1; 945 } 946#endif 947#endif /* AUTHENTICATION */ 948} 949 950#ifndef O_NOCTTY 951#define O_NOCTTY 0 952#endif 953/* 954 * Open the specified slave side of the pty, 955 * making sure that we have a clean tty. 956 */ 957int 958cleanopen(char *li) 959{ 960 int t; 961 962 /* 963 * Make sure that other people can't open the 964 * slave side of the connection. 965 */ 966 (void) chown(li, 0, 0); 967 (void) chmod(li, 0600); 968 969 (void) revoke(li); 970 971 t = open(line, O_RDWR|O_NOCTTY); 972 973 if (t < 0) 974 return(-1); 975 976 return(t); 977} 978 979/* 980 * startslave(host) 981 * 982 * Given a hostname, do whatever 983 * is necessary to startup the login process on the slave side of the pty. 984 */ 985 986/* ARGSUSED */ 987void 988startslave(char *host, int autologin, char *autoname) 989{ 990 int i; 991 992#ifdef AUTHENTICATION 993 if (!autoname || !autoname[0]) 994 autologin = 0; 995 996 if (autologin < auth_level) { 997 fatal(net, "Authorization failed"); 998 exit(1); 999 } 1000#endif 1001 1002 1003 if ((i = fork()) < 0) 1004 fatalperror(net, "fork"); 1005 if (i) { 1006 } else { 1007 getptyslave(); 1008 start_login(host, autologin, autoname); 1009 /*NOTREACHED*/ 1010 } 1011} 1012 1013void 1014init_env(void) 1015{ 1016 char **envp; 1017 1018 envp = envinit; 1019 if ((*envp = getenv("TZ"))) 1020 *envp++ -= 3; 1021 *envp = 0; 1022 environ = envinit; 1023} 1024 1025 1026/* 1027 * start_login(host) 1028 * 1029 * Assuming that we are now running as a child processes, this 1030 * function will turn us into the login process. 1031 */ 1032 1033#ifndef AUTHENTICATION 1034#define undef1 __unused 1035#else 1036#define undef1 1037#endif 1038 1039void 1040start_login(char *host undef1, int autologin undef1, char *name undef1) 1041{ 1042 char **argv; 1043 1044 scrub_env(); 1045 1046 /* 1047 * -h : pass on name of host. 1048 * WARNING: -h is accepted by login if and only if 1049 * getuid() == 0. 1050 * -p : don't clobber the environment (so terminal type stays set). 1051 * 1052 * -f : force this login, he has already been authenticated 1053 */ 1054 argv = addarg(0, "login"); 1055 1056#if !defined(NO_LOGIN_H) 1057#ifdef AUTHENTICATION 1058# if defined(NO_LOGIN_F) && defined(LOGIN_R) 1059 /* 1060 * Don't add the "-h host" option if we are going 1061 * to be adding the "-r host" option down below... 1062 */ 1063 if ((auth_level < 0) || (autologin != AUTH_VALID)) 1064# endif 1065 { 1066 argv = addarg(argv, "-h"); 1067 argv = addarg(argv, host); 1068 } 1069#endif /* AUTHENTICATION */ 1070#endif 1071#if !defined(NO_LOGIN_P) 1072 argv = addarg(argv, "-p"); 1073#endif 1074#ifdef LINEMODE 1075 /* 1076 * Set the environment variable "LINEMODE" to either 1077 * "real" or "kludge" if we are operating in either 1078 * real or kludge linemode. 1079 */ 1080 if (lmodetype == REAL_LINEMODE) 1081 setenv("LINEMODE", "real", 1); 1082# ifdef KLUDGELINEMODE 1083 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 1084 setenv("LINEMODE", "kludge", 1); 1085# endif 1086#endif 1087#ifdef BFTPDAEMON 1088 /* 1089 * Are we working as the bftp daemon? If so, then ask login 1090 * to start bftp instead of shell. 1091 */ 1092 if (bftpd) { 1093 argv = addarg(argv, "-e"); 1094 argv = addarg(argv, BFTPPATH); 1095 } else 1096#endif 1097#ifdef AUTHENTICATION 1098 if (auth_level >= 0 && autologin == AUTH_VALID) { 1099# if !defined(NO_LOGIN_F) 1100 argv = addarg(argv, "-f"); 1101 argv = addarg(argv, "--"); 1102 argv = addarg(argv, name); 1103# else 1104# if defined(LOGIN_R) 1105 /* 1106 * We don't have support for "login -f", but we 1107 * can fool /bin/login into thinking that we are 1108 * rlogind, and allow us to log in without a 1109 * password. The rlogin protocol expects 1110 * local-user\0remote-user\0term/speed\0 1111 */ 1112 1113 if (pty > 2) { 1114 char *cp; 1115 char speed[128]; 1116 int isecho, israw, xpty, len; 1117 extern int def_rspeed; 1118# ifndef LOGIN_HOST 1119 /* 1120 * Tell login that we are coming from "localhost". 1121 * If we passed in the real host name, then the 1122 * user would have to allow .rhost access from 1123 * every machine that they want authenticated 1124 * access to work from, which sort of defeats 1125 * the purpose of an authenticated login... 1126 * So, we tell login that the session is coming 1127 * from "localhost", and the user will only have 1128 * to have "localhost" in their .rhost file. 1129 */ 1130# define LOGIN_HOST "localhost" 1131# endif 1132 argv = addarg(argv, "-r"); 1133 argv = addarg(argv, LOGIN_HOST); 1134 1135 xpty = pty; 1136 pty = 0; 1137 init_termbuf(); 1138 isecho = tty_isecho(); 1139 israw = tty_israw(); 1140 if (isecho || !israw) { 1141 tty_setecho(0); /* Turn off echo */ 1142 tty_setraw(1); /* Turn on raw */ 1143 set_termbuf(); 1144 } 1145 len = strlen(name)+1; 1146 write(xpty, name, len); 1147 write(xpty, name, len); 1148 snprintf(speed, sizeof(speed), 1149 "%s/%d", (cp = getenv("TERM")) ? cp : "", 1150 (def_rspeed > 0) ? def_rspeed : 9600); 1151 len = strlen(speed)+1; 1152 write(xpty, speed, len); 1153 1154 if (isecho || !israw) { 1155 init_termbuf(); 1156 tty_setecho(isecho); 1157 tty_setraw(israw); 1158 set_termbuf(); 1159 if (!israw) { 1160 /* 1161 * Write a newline to ensure 1162 * that login will be able to 1163 * read the line... 1164 */ 1165 write(xpty, "\n", 1); 1166 } 1167 } 1168 pty = xpty; 1169 } 1170# else 1171 argv = addarg(argv, "--"); 1172 argv = addarg(argv, name); 1173# endif 1174# endif 1175 } else 1176#endif 1177 if (getenv("USER")) { 1178 argv = addarg(argv, "--"); 1179 argv = addarg(argv, getenv("USER")); 1180#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) 1181 { 1182 char **cpp; 1183 for (cpp = environ; *cpp; cpp++) 1184 argv = addarg(argv, *cpp); 1185 } 1186#endif 1187 /* 1188 * Assume that login will set the USER variable 1189 * correctly. For SysV systems, this means that 1190 * USER will no longer be set, just LOGNAME by 1191 * login. (The problem is that if the auto-login 1192 * fails, and the user then specifies a different 1193 * account name, he can get logged in with both 1194 * LOGNAME and USER in his environment, but the 1195 * USER value will be wrong. 1196 */ 1197 unsetenv("USER"); 1198 } 1199#ifdef AUTHENTICATION 1200#if defined(NO_LOGIN_F) && defined(LOGIN_R) 1201 if (pty > 2) 1202 close(pty); 1203#endif 1204#endif /* AUTHENTICATION */ 1205 closelog(); 1206 1207 if (altlogin == NULL) { 1208 altlogin = _PATH_LOGIN; 1209 } 1210 execv(altlogin, argv); 1211 1212 syslog(LOG_ERR, "%s: %m", altlogin); 1213 fatalperror(net, altlogin); 1214 /*NOTREACHED*/ 1215} 1216 1217static char ** 1218addarg(char **argv, const char *val) 1219{ 1220 char **cpp; 1221 1222 if (argv == NULL) { 1223 /* 1224 * 10 entries, a leading length, and a null 1225 */ 1226 argv = (char **)malloc(sizeof(*argv) * 12); 1227 if (argv == NULL) 1228 return(NULL); 1229 *argv++ = (char *)10; 1230 *argv = (char *)0; 1231 } 1232 for (cpp = argv; *cpp; cpp++) 1233 ; 1234 if (cpp == &argv[(long)argv[-1]]) { 1235 --argv; 1236 *argv = (char *)((long)(*argv) + 10); 1237 argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2)); 1238 if (argv == NULL) 1239 return(NULL); 1240 argv++; 1241 cpp = &argv[(long)argv[-1] - 10]; 1242 } 1243 *cpp++ = strdup(val); 1244 *cpp = 0; 1245 return(argv); 1246} 1247 1248/* 1249 * scrub_env() 1250 * 1251 * We only accept the environment variables listed below. 1252 */ 1253void 1254scrub_env(void) 1255{ 1256 static const char *rej[] = { 1257 "TERMCAP=/", 1258 NULL 1259 }; 1260 1261 static const char *acc[] = { 1262 "XAUTH=", "XAUTHORITY=", "DISPLAY=", 1263 "TERM=", 1264 "EDITOR=", 1265 "PAGER=", 1266 "LOGNAME=", 1267 "POSIXLY_CORRECT=", 1268 "PRINTER=", 1269 NULL 1270 }; 1271 1272 char **cpp, **cpp2; 1273 const char **p; 1274 1275 for (cpp2 = cpp = environ; *cpp; cpp++) { 1276 int reject_it = 0; 1277 1278 for(p = rej; *p; p++) 1279 if(strncmp(*cpp, *p, strlen(*p)) == 0) { 1280 reject_it = 1; 1281 break; 1282 } 1283 if (reject_it) 1284 continue; 1285 1286 for(p = acc; *p; p++) 1287 if(strncmp(*cpp, *p, strlen(*p)) == 0) 1288 break; 1289 if(*p != NULL) 1290 *cpp2++ = *cpp; 1291 } 1292 *cpp2 = NULL; 1293} 1294 1295/* 1296 * cleanup() 1297 * 1298 * This is the routine to call when we are all through, to 1299 * clean up anything that needs to be cleaned up. 1300 */ 1301/* ARGSUSED */ 1302void 1303cleanup(int sig __unused) 1304{ 1305 char *p; 1306 sigset_t mask; 1307 1308 p = line + sizeof(_PATH_DEV) - 1; 1309 /* 1310 * Block all signals before clearing the utmp entry. We don't want to 1311 * be called again after calling logout() and then not add the wtmp 1312 * entry because of not finding the corresponding entry in utmp. 1313 */ 1314 sigfillset(&mask); 1315 sigprocmask(SIG_SETMASK, &mask, NULL); 1316 if (logout(p)) 1317 logwtmp(p, "", ""); 1318 (void)chmod(line, 0666); 1319 (void)chown(line, 0, 0); 1320 *p = 'p'; 1321 (void)chmod(line, 0666); 1322 (void)chown(line, 0, 0); 1323 (void) shutdown(net, 2); 1324 _exit(1); 1325} 1326