/* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* baesd on @(#)sys_term.c 8.1 (Berkeley) 6/4/93 */ #include "telnetd.h" #include "pathnames.h" #include #ifndef LOGIN_PROGRAM #define LOGIN_PROGRAM _PATH_LOGIN #endif #include #if defined(AUTHENTICATION) #include #endif #if defined(KRB5) #include "k5-int.h" #endif char *login_program = LOGIN_PROGRAM; #ifdef NEWINIT #include int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */ #else /* NEWINIT*/ #ifdef HAVE_UTMP_H #include #endif #ifdef _PATH_WTMP char wtmpf[] = _PATH_WTMP; #else char wtmpf[] = "/usr/adm/wtmp"; #endif #ifdef _PATH_UTMP char utmpf[] = _PATH_UTMP; #else char utmpf[] = "/etc/utmp"; #endif # ifdef CRAY #include #include # if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY) /* * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can * use it to tell us to turn off all the socket security code, * since that is only used in UNICOS 7.0 and later. */ # undef _SC_CRAY_SECURE_SYS # endif # if defined(_SC_CRAY_SECURE_SYS) #include #include extern int secflag; extern struct sysv sysv; # endif /* _SC_CRAY_SECURE_SYS */ # endif /* CRAY */ #endif /* NEWINIT */ #ifdef STREAMSPTY #ifdef HAVE_SAC_H #include #endif #include #endif #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) #define SCMPN(a, b) strncmp(a, b, sizeof(a)) #ifdef HAVE_SYS_STREAM_H #include #endif #ifdef __hpux #include #include #endif /* For what platforms do we really need sys/tty.h? */ #ifdef HAVE_SYS_TTY_H #include #endif #ifdef t_erase #undef t_erase #undef t_kill #undef t_intrc #undef t_quitc #undef t_startc #undef t_stopc #undef t_eofc #undef t_brkc #undef t_suspc #undef t_dsuspc #undef t_rprntc #undef t_flushc #undef t_werasc #undef t_lnextc #endif #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC) # define EXTPROC 0400 #endif #ifndef USE_TERMIO struct termbuf { struct sgttyb sg; struct tchars tc; struct ltchars ltc; int state; int lflags; } termbuf, termbuf2; # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) # define cfgetospeed(tp) (tp)->sg.sg_ospeed # define cfgetispeed(tp) (tp)->sg.sg_ispeed #else /* USE_TERMIO */ # ifdef SYSV_TERMIO # define termios termio # endif # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, t) # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (tp)->c_cflag |= (val) # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) # ifdef CIBAUD # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ (tp)->c_cflag |= ((val)<c_cflag & CIBAUD)>>IBSHIFT) # else # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (tp)->c_cflag |= (val) # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) # endif # endif /* TCSANOW */ struct termios termbuf, termbuf2; /* pty control structure */ # ifdef STREAMSPTY int ttyfd = -1; # endif #endif /* USE_TERMIO */ #ifndef SETPGRP_TWOARG #define setpgrp(a,b) setpgrp() #endif /* * init_termbuf() * copy_termbuf(cp) * set_termbuf() * * These three routines are used to get and set the "termbuf" structure * to and from the kernel. init_termbuf() gets the current settings. * copy_termbuf() hands in a new "termbuf" to write to the kernel, and * set_termbuf() writes the structure into the kernel. */ void init_termbuf() { #ifndef USE_TERMIO (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); # ifdef TIOCGSTATE (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); # endif #else # ifdef STREAMSPTY (void) tcgetattr(ttyfd, &termbuf); # else (void) tcgetattr(pty, &termbuf); # endif #endif termbuf2 = termbuf; } #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) void copy_termbuf(cp, len) char *cp; int len; { if (len > sizeof(termbuf)) len = sizeof(termbuf); memcpy((char *)&termbuf, cp, len); termbuf2 = termbuf; } #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ void set_termbuf() { /* * Only make the necessary changes. */ #ifndef USE_TERMIO if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, sizeof(termbuf.ltc))) (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); if (termbuf.lflags != termbuf2.lflags) (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); #else /* USE_TERMIO */ if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) # ifdef STREAMSPTY (void) tcsetattr(ttyfd, TCSANOW, &termbuf); # else (void) tcsetattr(pty, TCSANOW, &termbuf); # endif # if defined(CRAY2) && defined(UNICOS5) needtermstat = 1; # endif #endif /* USE_TERMIO */ } /* * spcset(func, valp, valpp) * * This function takes various special characters (func), and * sets *valp to the current value of that character, and * *valpp to point to where in the "termbuf" structure that * value is kept. * * It returns the SLC_ level of support for this function. */ #ifndef USE_TERMIO int spcset(func, valp, valpp) int func; cc_t *valp; cc_t **valpp; { switch(func) { case SLC_EOF: *valp = termbuf.tc.t_eofc; *valpp = (cc_t *)&termbuf.tc.t_eofc; return(SLC_VARIABLE); case SLC_EC: *valp = termbuf.sg.sg_erase; *valpp = (cc_t *)&termbuf.sg.sg_erase; return(SLC_VARIABLE); case SLC_EL: *valp = termbuf.sg.sg_kill; *valpp = (cc_t *)&termbuf.sg.sg_kill; return(SLC_VARIABLE); case SLC_IP: *valp = termbuf.tc.t_intrc; *valpp = (cc_t *)&termbuf.tc.t_intrc; return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); case SLC_ABORT: *valp = termbuf.tc.t_quitc; *valpp = (cc_t *)&termbuf.tc.t_quitc; return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); case SLC_XON: *valp = termbuf.tc.t_startc; *valpp = (cc_t *)&termbuf.tc.t_startc; return(SLC_VARIABLE); case SLC_XOFF: *valp = termbuf.tc.t_stopc; *valpp = (cc_t *)&termbuf.tc.t_stopc; return(SLC_VARIABLE); case SLC_AO: *valp = termbuf.ltc.t_flushc; *valpp = (cc_t *)&termbuf.ltc.t_flushc; return(SLC_VARIABLE); case SLC_SUSP: *valp = termbuf.ltc.t_suspc; *valpp = (cc_t *)&termbuf.ltc.t_suspc; return(SLC_VARIABLE); case SLC_EW: *valp = termbuf.ltc.t_werasc; *valpp = (cc_t *)&termbuf.ltc.t_werasc; return(SLC_VARIABLE); case SLC_RP: *valp = termbuf.ltc.t_rprntc; *valpp = (cc_t *)&termbuf.ltc.t_rprntc; return(SLC_VARIABLE); case SLC_LNEXT: *valp = termbuf.ltc.t_lnextc; *valpp = (cc_t *)&termbuf.ltc.t_lnextc; return(SLC_VARIABLE); case SLC_FORW1: *valp = termbuf.tc.t_brkc; *valpp = (cc_t *)&termbuf.ltc.t_lnextc; return(SLC_VARIABLE); case SLC_BRK: case SLC_SYNCH: case SLC_AYT: case SLC_EOR: *valp = (cc_t)0; *valpp = (cc_t *)0; return(SLC_DEFAULT); default: *valp = (cc_t)0; *valpp = (cc_t *)0; return(SLC_NOSUPPORT); } } #else /* USE_TERMIO */ int spcset(func, valp, valpp) int func; cc_t *valp; cc_t **valpp; { #define setval(a, b) *valp = termbuf.c_cc[a]; \ *valpp = &termbuf.c_cc[a]; \ return(b); #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); switch(func) { case SLC_EOF: setval(VEOF, SLC_VARIABLE); case SLC_EC: setval(VERASE, SLC_VARIABLE); case SLC_EL: setval(VKILL, SLC_VARIABLE); case SLC_IP: setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); case SLC_ABORT: setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); case SLC_XON: #ifdef VSTART setval(VSTART, SLC_VARIABLE); #else defval(0x13); #endif case SLC_XOFF: #ifdef VSTOP setval(VSTOP, SLC_VARIABLE); #else defval(0x11); #endif case SLC_EW: #ifdef VWERASE setval(VWERASE, SLC_VARIABLE); #else defval(0); #endif case SLC_RP: #ifdef VREPRINT setval(VREPRINT, SLC_VARIABLE); #else defval(0); #endif case SLC_LNEXT: #ifdef VLNEXT setval(VLNEXT, SLC_VARIABLE); #else defval(0); #endif case SLC_AO: #if !defined(VDISCARD) && defined(VFLUSHO) # define VDISCARD VFLUSHO #endif #ifdef VDISCARD setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); #else defval(0); #endif case SLC_SUSP: #ifdef VSUSP setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); #else defval(0); #endif #ifdef VEOL case SLC_FORW1: setval(VEOL, SLC_VARIABLE); #endif #ifdef VEOL2 case SLC_FORW2: setval(VEOL2, SLC_VARIABLE); #endif case SLC_AYT: #ifdef VSTATUS setval(VSTATUS, SLC_VARIABLE); #else defval(0); #endif case SLC_BRK: case SLC_SYNCH: case SLC_EOR: defval(0); default: *valp = 0; *valpp = 0; return(SLC_NOSUPPORT); } } #endif /* USE_TERMIO */ #ifdef CRAY /* * getnpty() * * Return the number of pty's configured into the system. */ int getnpty() { #ifdef _SC_CRAY_NPTY int numptys; if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) return numptys; else #endif /* _SC_CRAY_NPTY */ return 128; } #endif /* CRAY */ #ifndef convex /* * getpty() * * Allocate a pty. As a side effect, the external character * array "line" contains the name of the slave side. * * Returns the file descriptor of the opened pty. */ static char Xline[17]; char *line = Xline; #ifdef CRAY char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #endif /* CRAY */ #endif /* convex */ static pid_t slavepid = 0; #ifdef LINEMODE /* * tty_flowmode() Find out if flow control is enabled or disabled. * tty_linemode() Find out if linemode (external processing) is enabled. * tty_setlinemod(on) Turn on/off linemode. * tty_isecho() Find out if echoing is turned on. * tty_setecho(on) Enable/disable character echoing. * tty_israw() Find out if terminal is in RAW mode. * tty_binaryin(on) Turn on/off BINARY on input. * tty_binaryout(on) Turn on/off BINARY on output. * tty_isediting() Find out if line editing is enabled. * tty_istrapsig() Find out if signal trapping is enabled. * tty_setedit(on) Turn on/off line editing. * tty_setsig(on) Turn on/off signal trapping. * tty_issofttab() Find out if tab expansion is enabled. * tty_setsofttab(on) Turn on/off soft tab expansion. * tty_islitecho() Find out if typed control chars are echoed literally * tty_setlitecho() Turn on/off literal echo of control chars * tty_tspeed(val) Set transmit speed to val. * tty_rspeed(val) Set receive speed to val. */ #ifdef convex static int linestate; #endif int tty_linemode() { #ifndef convex #ifndef USE_TERMIO return(termbuf.state & TS_EXTPROC); #else return(termbuf.c_lflag & EXTPROC); #endif #else return(linestate); #endif } void tty_setlinemode(on) int on; { #ifdef TIOCEXT # ifndef convex set_termbuf(); # else linestate = on; # endif (void) ioctl(pty, TIOCEXT, (char *)&on); # ifndef convex init_termbuf(); # endif #else /* !TIOCEXT */ # ifdef EXTPROC if (on) termbuf.c_lflag |= EXTPROC; else termbuf.c_lflag &= ~EXTPROC; # endif #endif /* TIOCEXT */ } #endif /* LINEMODE */ int tty_isecho() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & ECHO); #else return (termbuf.c_lflag & ECHO); #endif } int tty_flowmode() { #ifndef USE_TERMIO return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); #else return((termbuf.c_iflag & IXON) ? 1 : 0); #endif } int tty_restartany() { #ifndef USE_TERMIO # ifdef DECCTQ return((termbuf.lflags & DECCTQ) ? 0 : 1); # else return(-1); # endif #else return((termbuf.c_iflag & IXANY) ? 1 : 0); #endif } void tty_setecho(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= ECHO|CRMOD; else termbuf.sg.sg_flags &= ~(ECHO|CRMOD); #else if (on) termbuf.c_lflag |= ECHO; else termbuf.c_lflag &= ~ECHO; #endif } int tty_israw() { #ifndef USE_TERMIO return(termbuf.sg.sg_flags & RAW); #else return(!(termbuf.c_lflag & ICANON)); #endif } #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) int tty_setraw(on) { # ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= RAW; else termbuf.sg.sg_flags &= ~RAW; # else if (on) termbuf.c_lflag &= ~ICANON; else termbuf.c_lflag |= ICANON; # endif } #endif void tty_binaryin(on) int on; { #ifndef USE_TERMIO if (on) termbuf.lflags |= LPASS8; else termbuf.lflags &= ~LPASS8; #else if (on) { termbuf.c_iflag &= ~ISTRIP; } else { termbuf.c_iflag |= ISTRIP; } #endif } void tty_binaryout(on) int on; { #ifndef USE_TERMIO if (on) termbuf.lflags |= LLITOUT; else termbuf.lflags &= ~LLITOUT; #else if (on) { termbuf.c_cflag &= ~(CSIZE|PARENB); termbuf.c_cflag |= CS8; termbuf.c_oflag &= ~OPOST; } else { termbuf.c_cflag &= ~CSIZE; termbuf.c_cflag |= CS7|PARENB; termbuf.c_oflag |= OPOST; } #endif } int tty_isbinaryin() { #ifndef USE_TERMIO return(termbuf.lflags & LPASS8); #else return(!(termbuf.c_iflag & ISTRIP)); #endif } int tty_isbinaryout() { #ifndef USE_TERMIO return(termbuf.lflags & LLITOUT); #else return(!(termbuf.c_oflag&OPOST)); #endif } #ifdef LINEMODE int tty_isediting() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); #else return(termbuf.c_lflag & ICANON); #endif } int tty_istrapsig() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags&RAW)); #else return(termbuf.c_lflag & ISIG); #endif } void tty_setedit(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags &= ~CBREAK; else termbuf.sg.sg_flags |= CBREAK; #else if (on) termbuf.c_lflag |= ICANON; else termbuf.c_lflag &= ~ICANON; #endif } void tty_setsig(on) int on; { #ifndef USE_TERMIO if (on) ; #else if (on) termbuf.c_lflag |= ISIG; else termbuf.c_lflag &= ~ISIG; #endif } #endif /* LINEMODE */ int tty_issofttab() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & XTABS); #else # ifdef OXTABS return (termbuf.c_oflag & OXTABS); # endif # ifdef TABDLY return ((termbuf.c_oflag & TABDLY) == TAB3); # endif #endif } void tty_setsofttab(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= XTABS; else termbuf.sg.sg_flags &= ~XTABS; #else if (on) { # ifdef OXTABS termbuf.c_oflag |= OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB3; # endif } else { # ifdef OXTABS termbuf.c_oflag &= ~OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB0; # endif } #endif } int tty_islitecho() { #ifndef USE_TERMIO return (!(termbuf.lflags & LCTLECH)); #else # ifdef ECHOCTL return (!(termbuf.c_lflag & ECHOCTL)); # endif # ifdef TCTLECH return (!(termbuf.c_lflag & TCTLECH)); # endif # if !defined(ECHOCTL) && !defined(TCTLECH) return (0); /* assumes ctl chars are echoed '^x' */ # endif #endif } void tty_setlitecho(on) int on; { #ifndef USE_TERMIO if (on) termbuf.lflags &= ~LCTLECH; else termbuf.lflags |= LCTLECH; #else # ifdef ECHOCTL if (on) termbuf.c_lflag &= ~ECHOCTL; else termbuf.c_lflag |= ECHOCTL; # endif # ifdef TCTLECH if (on) termbuf.c_lflag &= ~TCTLECH; else termbuf.c_lflag |= TCTLECH; # endif #endif } int tty_iscrnl() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & CRMOD); #else return (termbuf.c_iflag & ICRNL); #endif } /* * A table of available terminal speeds */ struct termspeeds { int speed; int value; } termspeeds[] = { { 0, B0 }, { 50, B50 }, { 75, B75 }, { 110, B110 }, { 134, B134 }, { 150, B150 }, { 200, B200 }, { 300, B300 }, { 600, B600 }, { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 }, { 38400, B9600 }, { -1, B9600 } }; void tty_tspeed(val) int val; { register struct termspeeds *tp; for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) ; cfsetospeed(&termbuf, tp->value); } void tty_rspeed(val) int val; { register struct termspeeds *tp; for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) ; cfsetispeed(&termbuf, tp->value); } #if defined(CRAY2) && defined(UNICOS5) int tty_isnewmap() { return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && !(termbuf.c_oflag & ONLRET)); } #endif #ifndef NEWINIT #endif /* * getptyslave() * * Open the slave side of the pty, and do any initialization * that is necessary. The return value is a file descriptor * for the slave side. */ int getptyslave() { int t = -1; long retval; #if !defined(CRAY) || !defined(NEWINIT) # ifdef LINEMODE int waslm; # endif # ifdef TIOCGWINSZ struct winsize ws; extern int def_row, def_col; # endif extern int def_tspeed, def_rspeed; /* * Opening the slave side may cause initilization of the * kernel tty structure. We need remember the state of * if linemode was turned on * terminal window size * terminal speed * so that we can re-set them if we need to. */ # ifdef LINEMODE waslm = tty_linemode(); # endif if ( (retval = pty_open_slave (line, &t)) != 0 ) { fatalperror(net, error_message(retval)); } #ifdef STREAMSPTY #ifdef USE_TERMIO ttyfd = t; #endif if (ioctl(pty, I_PUSH, "pckt") < 0) fatal(net, "I_PUSH pckt"); #endif /* * set up the tty modes as we like them to be. */ init_termbuf(); # ifdef TIOCGWINSZ if (def_row || def_col) { memset((char *)&ws, 0, sizeof(ws)); ws.ws_col = def_col; ws.ws_row = def_row; (void)ioctl(t, TIOCSWINSZ, (char *)&ws); } # endif /* * Settings for sgtty based systems */ # ifndef USE_TERMIO termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; # endif /* USE_TERMIO */ /* * Settings for UNICOS (and HPUX) */ # if defined(CRAY) || defined(__hpux) termbuf.c_oflag = OPOST|ONLCR|TAB3; termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; termbuf.c_cflag = EXTB|HUPCL|CS8; # endif /* * Settings for all other termios/termio based * systems, other than 4.4BSD. In 4.4BSD the * kernel does the initial terminal setup. */ # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) # ifndef OXTABS # define OXTABS 0 # endif termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG; termbuf.c_oflag |= ONLCR|OXTABS|OPOST; termbuf.c_iflag |= ICRNL|IGNPAR; termbuf.c_cflag |= HUPCL; termbuf.c_iflag &= ~IXOFF; # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */ tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); # ifdef LINEMODE if (waslm) tty_setlinemode(1); # endif /* LINEMODE */ /* * Set the tty modes, and make this our controlling tty. */ set_termbuf(); if (dup_tty(t) == -1) fatalperror(net, "dup_tty"); #endif /* !defined(CRAY) || !defined(NEWINIT) */ if (net > 2) (void) close(net); #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) /* * Leave the pty open so that we can write out the rlogin * protocol for /bin/login, if the authentication works. */ #else if (pty > 2) { (void) close(pty); pty = -1; } #endif } #if !defined(CRAY) || !defined(NEWINIT) #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #endif /* !defined(CRAY) || !defined(NEWINIT) */ int dup_tty(t) int t; { if (t != 0) (void) dup2(t, 0); if (t != 1) (void) dup2(t, 1); if (t != 2) (void) dup2(t, 2); if (t > 2) close(t); return(0); } #ifdef NEWINIT char *gen_id = "fe"; #endif /* * startslave(host) * * Given a hostname, do whatever * is necessary to startup the login process on the slave side of the pty. */ /* ARGSUSED */ void startslave(host, autologin, autoname) char *host; int autologin; char *autoname; { int syncpipe[2]; register int i; #ifdef NEWINIT extern char *ptyip; struct init_request request; void nologinproc(); register int n; #endif /* NEWINIT */ if ( pipe(syncpipe) < 0 ) fatal(net, "failed getting synchronization pipe"); #if defined(AUTHENTICATION) if (!autoname || !autoname[0]) autologin = 0; if (autologin < auth_level) { fatal(net, "Authorization failed"); exit(1); } #endif #ifndef NEWINIT if ((i = fork()) < 0) fatalperror(net, "fork"); if (i) { char c; void sigjob P((int)); slavepid = i; /* So we can clean it up later */ #ifdef CRAY (void) signal(WJSIGNAL, sigjob); #endif /* Wait for child before writing to parent side of pty.*/ (void) close(syncpipe[1]); if ( read(syncpipe[0], &c, 1) == 0 ) { /* Slave side died */ fatal ( net, "Slave failed to initialize"); } close(syncpipe[0]); } else { pty_update_utmp (PTY_LOGIN_PROCESS, getpid(), "LOGIN", line, host, PTY_TTYSLOT_USABLE); getptyslave(autologin); /* Notify our parent we're ready to continue.*/ write(syncpipe[1],"y",1); close(syncpipe[0]); close(syncpipe[1]); start_login(host, autologin, autoname); /*NOTREACHED*/ } #else /* NEWINIT */ /* * Init will start up login process if we ask nicely. We only wait * for it to start up and begin normal telnet operation. */ if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { char tbuf[128]; (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); fatalperror(net, tbuf); } memset((char *)&request, 0, sizeof(request)); request.magic = INIT_MAGIC; SCPYN(request.gen_id, gen_id); SCPYN(request.tty_id, &line[8]); SCPYN(request.host, host); SCPYN(request.term_type, *terminaltype ? terminaltype : "network"); #if !defined(UNICOS5) request.signal = SIGCLD; request.pid = getpid(); #endif #ifdef BFTPDAEMON /* * Are we working as the bftp daemon? */ if (bftpd) { SCPYN(request.exec_name, BFTPPATH); } #endif /* BFTPDAEMON */ if (write(i, (char *)&request, sizeof(request)) < 0) { char tbuf[128]; (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); fatalperror(net, tbuf); } (void) close(i); (void) signal(SIGALRM, nologinproc); for (i = 0; ; i++) { char tbuf[128]; alarm(15); n = read(pty, ptyip, BUFSIZ); if (i == 3 || n >= 0 || !gotalarm) break; gotalarm = 0; sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); (void) write(net, tbuf, strlen(tbuf)); } if (n < 0 && gotalarm) fatal(net, "/etc/init didn't start login process"); pcc += n; alarm(0); (void) signal(SIGALRM, SIG_DFL); return; #endif /* NEWINIT */ } char *envinit[3]; extern char **environ; void init_env() { extern char *getenv(); char **envp; envp = envinit; if (*envp = getenv("TZ")) *envp++ -= 3; #if defined(CRAY) || defined(__hpux) else *envp++ = "TZ=GMT0"; #endif *envp = 0; environ = envinit; } #ifndef NEWINIT /* * start_login(host) * * Assuming that we are now running as a child processes, this * function will turn us into the login process. */ void start_login(host, autologin, name) char *host; int autologin; char *name; { register char *cp; register char **argv; char **addarg(); extern char *getenv(); register int pid = getpid(); #ifdef SOLARIS char *term; char termbuf[64]; #endif /* * -h : pass on name of host. * WARNING: -h is accepted by login if and only if * getuid() == 0. * -p : don't clobber the environment (so terminal type stays set). * * -f : force this login, he has already been authenticated */ argv = addarg(0, "login"); #if !defined(NO_LOGIN_H) # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) /* * Don't add the "-h host" option if we are going * to be adding the "-r host" option down below... */ if ((auth_level < 0) || (autologin != AUTH_VALID)) # endif { argv = addarg(argv, "-h"); argv = addarg(argv, host); #ifdef SOLARIS /* * SVR4 version of -h takes TERM= as second arg, or - */ term = getenv("TERM"); if (term == NULL || term[0] == 0) { term = "-"; } else { strcpy(termbuf, "TERM="); strncat(termbuf, term, sizeof(termbuf) - 6); term = termbuf; } argv = addarg(argv, term); #endif } #endif #if !defined(NO_LOGIN_P) argv = addarg(argv, "-p"); #endif #ifdef BFTPDAEMON /* * Are we working as the bftp daemon? If so, then ask login * to start bftp instead of shell. */ if (bftpd) { argv = addarg(argv, "-e"); argv = addarg(argv, BFTPPATH); } else #endif #if defined (SecurID) /* * don't worry about the -f that might get sent. * A -s is supposed to override it anyhow. */ if (require_SecurID) argv = addarg(argv, "-s"); #endif #if defined (AUTHENTICATION) if (auth_level >= 0 && autologin == AUTH_VALID) { # if !defined(NO_LOGIN_F) #if defined(LOGIN_CAP_F) argv = addarg(argv, "-F"); #else argv = addarg(argv, "-f"); #endif argv = addarg(argv, name); # else # if defined(LOGIN_R) /* * We don't have support for "login -f", but we * can fool /bin/login into thinking that we are * rlogind, and allow us to log in without a * password. The rlogin protocol expects * local-user\0remote-user\0term/speed\0 */ if (pty > 2) { register char *cp; char speed[1024]; int isecho, israw, xpty, len; extern int def_rspeed; # ifndef LOGIN_HOST /* * Tell login that we are coming from "localhost". * If we passed in the real host name, then the * user would have to allow .rhost access from * every machine that they want authenticated * access to work from, which sort of defeats * the purpose of an authenticated login... * So, we tell login that the session is coming * from "localhost", and the user will only have * to have "localhost" in their .rhost file. */ # define LOGIN_HOST "localhost" # endif argv = addarg(argv, "-r"); argv = addarg(argv, LOGIN_HOST); xpty = pty; # ifndef STREAMSPTY pty = 0; # else ttyfd = 0; # endif init_termbuf(); isecho = tty_isecho(); israw = tty_israw(); if (isecho || !israw) { tty_setecho(0); /* Turn off echo */ tty_setraw(1); /* Turn on raw */ set_termbuf(); } len = strlen(name)+1; write(xpty, name, len); write(xpty, name, len); memset(speed, 0, sizeof(speed)); strncpy(speed, (cp = getenv("TERM")) ? cp : "", sizeof(speed)-1-(10*sizeof(def_rspeed)/4)-1); /* 1 for /, () for the number, 1 for trailing 0. */ sprintf(speed + strlen(speed), "/%d", (def_rspeed > 0) ? def_rspeed : 9600); len = strlen(speed)+1; write(xpty, speed, len); if (isecho || !israw) { init_termbuf(); tty_setecho(isecho); tty_setraw(israw); set_termbuf(); if (!israw) { /* * Write a newline to ensure * that login will be able to * read the line... */ write(xpty, "\n", 1); } } pty = xpty; } # else argv = addarg(argv, name); # endif # endif } else #endif if (getenv("USER")) { argv = addarg(argv, getenv("USER")); #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) { register char **cpp; for (cpp = environ; *cpp; cpp++) argv = addarg(argv, *cpp); } #endif /* * Assume that login will set the USER variable * correctly. For SysV systems, this means that * USER will no longer be set, just LOGNAME by * login. (The problem is that if the auto-login * fails, and the user then specifies a different * account name, he can get logged in with both * LOGNAME and USER in his environment, but the * USER value will be wrong. */ unsetenv("USER"); } #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) if (pty > 2) close(pty); #endif closelog(); execv(login_program, argv); syslog(LOG_ERR, "%s: %m", login_program); fatalperror(net, login_program); /*NOTREACHED*/ } char ** addarg(argv, val) register char **argv; register char *val; { register char **cpp; if (argv == NULL) { /* * 10 entries, a leading length, and a null */ argv = (char **)malloc(sizeof(*argv) * 12); if (argv == NULL) return(NULL); *argv++ = (char *)10; *argv = (char *)0; } for (cpp = argv; *cpp; cpp++) ; if (cpp == &argv[(int)argv[-1]]) { --argv; *argv = (char *)((int)(*argv) + 10); argv = (char **)realloc(argv, (int)(*argv) + 2); if (argv == NULL) return(NULL); argv++; cpp = &argv[(int)argv[-1] - 10]; } *cpp++ = val; *cpp = 0; return(argv); } #endif /* NEWINIT */ /* * cleanup() * * This is the routine to call when we are all through, to * clean up anything that needs to be cleaned up. */ /* ARGSUSED */ void cleanup(sig) int sig; { pty_cleanup(line,slavepid,1); #ifdef KRB5 kerberos5_cleanup(); #endif (void) shutdown(net, 2); exit(1); }