/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. * * Copyright (c) 1989 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. 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. */ /* * From: @(#)sys_term.c 5.16 (Berkeley) 3/22/91 */ char st_rcsid[] = "$Id: sys_term.c,v 1.10 2007/09/22 20:57:50 arkenoi Exp $"; int auth_login(char hostaddr[]); #include #include #ifdef SOLARIS #include #include typedef void (*mysig_t)(int); #endif #include "telnetd.h" #if defined(__GLIBC__) && (__GLIBC__ >= 2) /* mmm, nonstandard */ #include #else int openpty(int *, int *, char *, struct termios *, struct winsize *); #endif #define ARCH64 ((sizeof(void *)) == 8) #define ARCH32 ((sizeof(void *)) == 4) static struct termios termbuf, termbuf2; /* pty control structure */ extern char authsrv_host[]; extern unsigned short int authsrv_port; /*static int cleanopen(char *line);*/ /* * 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(void) { tcgetattr(pty, &termbuf); termbuf2 = termbuf; } void set_termbuf(void) { if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) { tcsetattr(pty, TCSANOW, &termbuf); } } /* * 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. */ int spcset(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); } } /* * 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 linedata[PATH_MAX]; char *line = linedata; static int ptyslavefd=-1; int getpty(void) { int masterfd; #ifdef SOLARIS /* * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 * also has bsd-style ptys, but they simply do not work.) */ int ptm; char *pts; mysig_t old_signal; ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (ptm < 0) { syslog(LOG_ERR, "fwtksyserr: /dev/ptmx: %s", strerror(errno)); return -1; } old_signal = signal(SIGCHLD, SIG_DFL); if (grantpt(ptm) < 0) { syslog(LOG_ERR, "fwtksyserr: grantpt: %s", , strerror(errno)); return -1; } signal(SIGCHLD, old_signal); if (unlockpt(ptm) < 0) { syslog(LOG_ERR, "fwtksyserr: unlockpt: %s", , strerror(errno)); return -1; } pts = ptsname(ptm); if (pts == NULL) { syslog(LOG_ERR, "Slave pty side name could not be obtained."); } strncpy(line, pts, sizeof(linedata)); masterfd = ptm; /* Open the slave side. */ ptyslavefd = open(line, O_RDWR | O_NOCTTY); if (ptyslavefd < 0) { syslog(LOG_ERR, "fwtksyserr: %.100s: %s", line, , strerror(errno)); close(masterfd); return -1; } ioctl(ptyslavefd, I_PUSH, "ptem"); /* push ptem */ ioctl(ptyslavefd, I_PUSH, "ldterm"); /* push ldterm*/ ioctl(ptyslavefd, I_PUSH, "ttcompat"); /* push ttcompat*/ #else if (openpty(&masterfd, &ptyslavefd, line, NULL, NULL)) { return -1; } #endif return masterfd; } void tty_setecho(int on) { if (on) termbuf.c_lflag |= ECHO; else termbuf.c_lflag &= ~ECHO; } void tty_binaryin(int on) { if (on) { termbuf.c_iflag &= ~ISTRIP; } else { termbuf.c_iflag |= ISTRIP; } } void tty_binaryout(int on) { 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; } } int tty_isbinaryin(void) { return (!(termbuf.c_iflag & ISTRIP)); } int tty_isbinaryout(void) { return (!(termbuf.c_oflag&OPOST)); } int tty_issofttab(void) { #ifdef OXTABS return (termbuf.c_oflag & OXTABS); #endif #ifdef TABDLY return ((termbuf.c_oflag & TABDLY) == TAB3); #endif } void tty_setsofttab(int on) { 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 } } int tty_islitecho(void) { return (!(termbuf.c_lflag & ECHOCTL)); } void tty_setlitecho(int on) { if (on) termbuf.c_lflag &= ~ECHOCTL; else termbuf.c_lflag |= ECHOCTL; } int tty_iscrnl(void) { return (termbuf.c_iflag & ICRNL); } /* * 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(int val) { struct termspeeds *tp; for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++); cfsetospeed(&termbuf, tp->value); } void tty_rspeed(int val) { struct termspeeds *tp; for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++); cfsetispeed(&termbuf, tp->value); } /* * 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. */ #ifdef TIOCGWINSZ extern int def_row, def_col; #endif extern int def_tspeed, def_rspeed; static int getptyslave(void) { struct winsize ws; int t = ptyslavefd; /* * set up the tty modes as we like them to be. */ init_termbuf(); # ifdef TIOCGWINSZ if (def_row || def_col) { bzero((char *)&ws, sizeof(ws)); ws.ws_col = def_col; ws.ws_row = def_row; ioctl(t, TIOCSWINSZ, (char *)&ws); } # endif /* * Settings for all other termios/termio based * systems, other than 4.4BSD. In 4.4BSD the * kernel does the initial terminal setup. * * XXX what about linux? */ # ifndef OXTABS # define OXTABS 0 # endif termbuf.c_lflag |= ECHO; termbuf.c_oflag |= OPOST|ONLCR|OXTABS; termbuf.c_iflag |= ICRNL; termbuf.c_iflag &= ~IXOFF; tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); /* * Set the tty modes, and make this our controlling tty. */ set_termbuf(); if (login_tty(t) == -1) fatalperror(net, "login_tty"); if (net > 2) close(net); if (pty > 2) close(pty); return t; } int login_tty(int t) { if (setsid() < 0) fatalperror(net, "setsid()"); #if !defined(SOLARIS) && !defined(HPUX) /* MYCHANGE: Look at it later */ if (ioctl(t, TIOCSCTTY, (char *)0) < 0) { fatalperror(net, "ioctl(sctty)"); } #endif if (t != 0) dup2(t, 0); if (t != 1) dup2(t, 1); if (t != 2) dup2(t, 2); if (t > 2) close(t); return 0; } /* * startslave(host) * * Given a hostname, do whatever * is necessary to startup the login process on the slave side of the pty. */ /* ARGSUSED */ void startslave(char *host, int autologin) { int i; i = fork(); if (i < 0) fatalperror(net, "fork"); if (i) { /* parent */ signal(SIGHUP,SIG_IGN); close(ptyslavefd); } else { /* child */ signal(SIGHUP,SIG_IGN); getptyslave(); start_login(host, autologin); } } char *envinit[3]; void init_env(void) { char **envp; envp = envinit; if ((*envp = getenv("TZ"))!=NULL) *envp++ -= 3; *envp = 0; environ = envinit; } /* * start_login(host) * * Assuming that we are now running as a child processes, this * function will turn us into the login process. */ struct argv_stuff { const char **argv; int argc; int argmax; }; void start_login(char *host, int autologin) { (void)autologin; auth_login(host); exit(0); } /* * cleanup() * * This is the routine to call when we are all through, to * clean up anything that needs to be cleaned up. */ void cleanup(int sig) { char *p; (void)sig; p = line + sizeof("/dev/") - 1; /* * dholland 16-Aug-96 chmod the tty when not in use * This will make it harder to attach unwanted stuff to it * (which is a security risk) but will break some programs. */ chmod(line, 0600); chown(line, 0, 0); *p = 'p'; chmod(line, 0666); chown(line, 0, 0); shutdown(net, 2); exit(0); }