-/*
- * State for recv fsm
- */
-#define TS_DATA 0 /* base state */
-#define TS_IAC 1 /* look for double IAC's */
-#define TS_CR 2 /* CR-LF ->'s CR */
-#define TS_SB 3 /* throw away begin's... */
-#define TS_SE 4 /* ...end's (suboption negotiation) */
-#define TS_WILL 5 /* will option negotiation */
-#define TS_WONT 6 /* wont " */
-#define TS_DO 7 /* do " */
-#define TS_DONT 8 /* dont " */
-
-telrcv()
-{
- register int c;
- static int state = TS_DATA;
-
- while (ncc > 0) {
- if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
- return;
- c = *netip++ & 0377, ncc--;
- switch (state) {
-
- case TS_CR:
- state = TS_DATA;
- /* Strip off \n or \0 after a \r */
- if ((c == 0) || (c == '\n')) {
- break;
- }
- /* FALL THROUGH */
-
- case TS_DATA:
- if (c == IAC) {
- state = TS_IAC;
- break;
- }
- if (inter > 0)
- break;
- /*
- * We now map \r\n ==> \r for pragmatic reasons.
- * Many client implementations send \r\n when
- * the user hits the CarriageReturn key.
- *
- * We USED to map \r\n ==> \n, since \r\n says
- * that we want to be in column 1 of the next
- * printable line, and \n is the standard
- * unix way of saying that (\r is only good
- * if CRMOD is set, which it normally is).
- */
- if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
- state = TS_CR;
- }
- *pfrontp++ = c;
- break;
-
- case TS_IAC:
- switch (c) {
-
- /*
- * Send the process on the pty side an
- * interrupt. Do this with a NULL or
- * interrupt char; depending on the tty mode.
- */
- case IP:
- interrupt();
- break;
-
- case BREAK:
- sendbrk();
- break;
-
- /*
- * Are You There?
- */
- case AYT:
- strcpy(nfrontp, "\r\n[Yes]\r\n");
- nfrontp += 9;
- break;
-
- /*
- * Abort Output
- */
- case AO: {
- struct ltchars tmpltc;
-
- ptyflush(); /* half-hearted */
- ioctl(pty, TIOCGLTC, &tmpltc);
- if (tmpltc.t_flushc != '\377') {
- *pfrontp++ = tmpltc.t_flushc;
- }
- netclear(); /* clear buffer back */
- *nfrontp++ = IAC;
- *nfrontp++ = DM;
- neturg = nfrontp-1; /* off by one XXX */
- break;
- }
-
- /*
- * Erase Character and
- * Erase Line
- */
- case EC:
- case EL: {
- struct sgttyb b;
- char ch;
-
- ptyflush(); /* half-hearted */
- ioctl(pty, TIOCGETP, &b);
- ch = (c == EC) ?
- b.sg_erase : b.sg_kill;
- if (ch != '\377') {
- *pfrontp++ = ch;
- }
- break;
- }
-
- /*
- * Check for urgent data...
- */
- case DM:
- SYNCHing = stilloob(net);
- settimer(gotDM);
- break;
-
-
- /*
- * Begin option subnegotiation...
- */
- case SB:
- state = TS_SB;
- SB_CLEAR();
- continue;
-
- case WILL:
- state = TS_WILL;
- continue;
-
- case WONT:
- state = TS_WONT;
- continue;
-
- case DO:
- state = TS_DO;
- continue;
-
- case DONT:
- state = TS_DONT;
- continue;
-
- case IAC:
- *pfrontp++ = c;
- break;
- }
- state = TS_DATA;
- break;
-
- case TS_SB:
- if (c == IAC) {
- state = TS_SE;
- } else {
- SB_ACCUM(c);
- }
- break;
-
- case TS_SE:
- if (c != SE) {
- if (c != IAC) {
- SB_ACCUM(IAC);
- }
- SB_ACCUM(c);
- state = TS_SB;
- } else {
- SB_TERM();
- suboption(); /* handle sub-option */
- state = TS_DATA;
- }
- break;
-
- case TS_WILL:
- if (hisopts[c] != OPT_YES)
- willoption(c);
- state = TS_DATA;
- if (c == TELOPT_TSPEED)
- getterminalspeed();
- continue;
-
- case TS_WONT:
- if (hisopts[c] != OPT_NO)
- wontoption(c);
- state = TS_DATA;
- continue;
-
- case TS_DO:
- if (myopts[c] != OPT_YES)
- dooption(c);
- state = TS_DATA;
- continue;
-
- case TS_DONT:
- if (myopts[c] != OPT_NO) {
- dontoption(c);
- }
- state = TS_DATA;
- continue;
-
- default:
- syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
- printf("telnetd: panic state=%d\n", state);
- exit(1);
- }
- }
-}
-
-willoption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
-
- case TELOPT_BINARY:
- mode(RAW, 0);
- fmt = doopt;
- break;
-
- case TELOPT_ECHO:
- not42 = 0; /* looks like a 4.2 system */
- /*
- * Now, in a 4.2 system, to break them out of ECHOing
- * (to the terminal) mode, we need to send a "WILL ECHO".
- * Kludge upon kludge!
- */
- if (myopts[TELOPT_ECHO] == OPT_YES) {
- dooption(TELOPT_ECHO);
- }
- fmt = dont;
- break;
-
- case TELOPT_TTYPE:
- settimer(ttypeopt);
- if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
- hisopts[TELOPT_TTYPE] = OPT_YES;
- return;
- }
- fmt = doopt;
- break;
-
- case TELOPT_NAWS:
- case TELOPT_TSPEED:
- case TELOPT_LFLOW:
- case TELOPT_SGA:
- fmt = doopt;
- break;
-
- case TELOPT_TM:
- fmt = dont;
- break;
-
- default:
- fmt = dont;
- break;
- }
- if (fmt == doopt) {
- hisopts[option] = OPT_YES;
- } else {
- hisopts[option] = OPT_NO;
- }
- (void) sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (dont) - 2;
-}
-
-wontoption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
- case TELOPT_ECHO:
- not42 = 1; /* doesn't seem to be a 4.2 system */
- break;
-
- case TELOPT_BINARY:
- mode(0, RAW);
- break;
-
- case TELOPT_TTYPE:
- settimer(ttypeopt);
- break;
- }
-
- fmt = dont;
- hisopts[option] = OPT_NO;
- (void) sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (doopt) - 2;
-}
-
-dooption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
-
- case TELOPT_TM:
- fmt = wont;
- break;
-
- case TELOPT_ECHO:
- mode(ECHO|CRMOD, 0);
- fmt = will;
- break;
-
- case TELOPT_BINARY:
- mode(RAW, 0);
- fmt = will;
- break;
-
- case TELOPT_SGA:
- fmt = will;
- break;
-
- default:
- fmt = wont;
- break;
- }
- if (fmt == will) {
- myopts[option] = OPT_YES;
- } else {
- myopts[option] = OPT_NO;
- }
- (void) sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (doopt) - 2;
-}
-
-
-dontoption(option)
-int option;
-{
- char *fmt;
-
- switch (option) {
- case TELOPT_ECHO: /* we should stop echoing */
- mode(0, ECHO);
- fmt = wont;
- break;
-
- default:
- fmt = wont;
- break;
- }
-
- if (fmt = wont) {
- myopts[option] = OPT_NO;
- } else {
- myopts[option] = OPT_YES;
- }
- (void) sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (wont) - 2;
-}
-
-/*
- * Given a string, assign the "best" speed which we support.
- *
- * "Best" is defined as rounding up, unless what is presented is
- * higher than the highest.
- */
-
-string2speed(s)
- char *s;
-{
- /*
- * The order here is important. The index of each speed needs to
- * correspond with the sgtty structure value for that speed.
- *
- * Additionally, the search algorithm assumes the table is in
- * ascending sequence.
- */
- static int ttyspeeds[] = {
- 0, 50, 75, 110, 134, 150, 200, 300,
- 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 };
-#define NUMSPEEDS sizeof ttyspeeds/sizeof ttyspeeds[0]
- int i;
- int theirspeed = atoi(s);
-
- for (i = 0; i < NUMSPEEDS; i++) {
- if (ttyspeeds[i] == theirspeed) { /* Exact match */
- return(i);
- } else if (ttyspeeds[i] > theirspeed) {
- if (i > 0) {
- return i-1;
- }
- }
- }
- /* Their number is greater than any of our numbers */
- return(NUMSPEEDS-1);
-}
-
-/*
- * suboption()
- *
- * Look at the sub-option buffer, and try to be helpful to the other
- * side.
- *
- * Currently we recognize:
- *
- * Terminal type is
- * Terminal size
- * Terminal speed is
- */
-
-suboption()
-{
- switch (SB_GET()) {
- case TELOPT_TTYPE: { /* Yaaaay! */
- static char terminalname[5+41] = "TERM=";
-
- settimer(ttypesubopt);
-
- if (SB_GET() != TELQUAL_IS) {
- return; /* ??? XXX but, this is the most robust */
- }
-
- terminaltype = terminalname+strlen(terminalname);
-
- while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
- !SB_EOF()) {
- register int c;
-
- c = SB_GET();
- if (isupper(c)) {
- c = tolower(c);
- }
- *terminaltype++ = c; /* accumulate name */
- }
- *terminaltype = 0;
- terminaltype = terminalname;
- break;
- }
- case TELOPT_NAWS: {
- struct winsize win;
-
- ioctl(pty, TIOCGWINSZ, &win);
- settimer(ttypesubopt);
-
- syslog(LOG_INFO, "%x %x %x %x",
- subpointer[0],subpointer[1],subpointer[2],subpointer[3]);
- win.ws_col = SB_GET() << 8;
- win.ws_col |= SB_GET();
- win.ws_row = SB_GET() << 8;
- win.ws_row |= SB_GET();
- syslog(LOG_INFO, "col %d row %d", win.ws_col, win.ws_row);
- ioctl(pty, TIOCSWINSZ, &win);
- break;
- }
- case TELOPT_TSPEED: {
- char speeds[41],*cp=speeds;
- struct sgttyb b;
- int ispeed,ospeed;
- char *ispeeds,*ospeeds;
-
- if (SB_GET() != TELQUAL_IS) {
- return; /* ??? XXX but, this is the most robust */
- }
-
- ispeeds = NULL;
- ospeeds = speeds;
- ispeed = 0;
- ospeed = 0;
- while ((cp < (speeds + sizeof speeds-1)) && !SB_EOF()) {
- register int c;
-
- c = SB_GET();
- if (c == ',') {
- c = 0;
- ispeeds = cp+1;
- }
- *cp++ = c; /* accumulate name */
- }
- *cp = 0;
-
- if (ispeeds)
- ispeed = string2speed(ispeeds);
- if (ospeeds)
- ospeed = string2speed(ospeeds);
-
- if (ispeed && ospeed) {
- ioctl(pty, TIOCGETP, &b);
- b.sg_ospeed = ospeed;
- b.sg_ispeed = ispeed;
- ioctl(pty, TIOCSETP, &b);
- }
-
- break;
- }
- default:
- ;
- }
-}
-
-mode(on, off)
- int on, off;
-{
- struct sgttyb b;
-
- ptyflush();
- ioctl(pty, TIOCGETP, &b);
- b.sg_flags |= on;
- b.sg_flags &= ~off;
- ioctl(pty, TIOCSETP, &b);
-}