BSD 4_4_Lite1 release
[unix-history] / usr / src / libexec / telnetd / state.c
index 1a34b4f..2d327a5 100644 (file)
@@ -1,12 +1,38 @@
 /*
 /*
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * 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.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)state.c    5.12 (Berkeley) %G%";
+static char sccsid[] = "@(#)state.c    8.2 (Berkeley) 12/15/93";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -14,10 +40,10 @@ static char sccsid[] = "@(#)state.c 5.12 (Berkeley) %G%";
 #include <libtelnet/auth.h>
 #endif
 
 #include <libtelnet/auth.h>
 #endif
 
-char   doopt[] = { IAC, DO, '%', 'c', 0 };
-char   dont[] = { IAC, DONT, '%', 'c', 0 };
-char   will[] = { IAC, WILL, '%', 'c', 0 };
-char   wont[] = { IAC, WONT, '%', 'c', 0 };
+unsigned char  doopt[] = { IAC, DO, '%', 'c', 0 };
+unsigned char  dont[] = { IAC, DONT, '%', 'c', 0 };
+unsigned char  will[] = { IAC, WILL, '%', 'c', 0 };
+unsigned char  wont[] = { IAC, WONT, '%', 'c', 0 };
 int    not42 = 1;
 
 /*
 int    not42 = 1;
 
 /*
@@ -26,7 +52,7 @@ int   not42 = 1;
  */
 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
 
  */
 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
 
-#define        SB_CLEAR()      subpointer = subbuffer;
+#define        SB_CLEAR()      subpointer = subbuffer
 #define        SB_TERM()       { subend = subpointer; SB_CLEAR(); }
 #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                                *subpointer++ = (c); \
 #define        SB_TERM()       { subend = subpointer; SB_CLEAR(); }
 #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                                *subpointer++ = (c); \
@@ -35,6 +61,11 @@ unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
 #define        SB_EOF()        (subpointer >= subend)
 #define        SB_LEN()        (subend - subpointer)
 
 #define        SB_EOF()        (subpointer >= subend)
 #define        SB_LEN()        (subend - subpointer)
 
+#ifdef ENV_HACK
+unsigned char *subsave;
+#define SB_SAVE()      subsave = subpointer;
+#define        SB_RESTORE()    subpointer = subsave;
+#endif
 
 
 /*
 
 
 /*
@@ -63,10 +94,10 @@ telrcv()
                if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
                        break;
                c = *netip++ & 0377, ncc--;
                if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
                        break;
                c = *netip++ & 0377, ncc--;
-#if    defined(ENCRYPTION)
+#ifdef ENCRYPTION
                if (decrypt_input)
                        c = (*decrypt_input)(c);
                if (decrypt_input)
                        c = (*decrypt_input)(c);
-#endif
+#endif /* ENCRYPTION */
                switch (state) {
 
                case TS_CR:
                switch (state) {
 
                case TS_CR:
@@ -95,10 +126,10 @@ telrcv()
                         */
                        if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
                                int nc = *netip;
                         */
                        if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
                                int nc = *netip;
-#if    defined(ENCRYPTION)
+#ifdef ENCRYPTION
                                if (decrypt_input)
                                        nc = (*decrypt_input)(nc & 0xff);
                                if (decrypt_input)
                                        nc = (*decrypt_input)(nc & 0xff);
-#endif
+#endif /* ENCRYPTION */
 #ifdef LINEMODE
                                /*
                                 * If we are operating in linemode,
 #ifdef LINEMODE
                                /*
                                 * If we are operating in linemode,
@@ -111,10 +142,10 @@ telrcv()
                                } else
 #endif
                                {
                                } else
 #endif
                                {
-#if    defined(ENCRYPTION)
+#ifdef ENCRYPTION
                                        if (decrypt_input)
                                                (void)(*decrypt_input)(-1);
                                        if (decrypt_input)
                                                (void)(*decrypt_input)(-1);
-#endif
+#endif /* ENCRYPTION */
                                        state = TS_CR;
                                }
                        }
                                        state = TS_CR;
                                }
                        }
@@ -421,7 +452,7 @@ send_do(option, init)
                        set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
                        set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, doopt, option);
+       (void) sprintf(nfrontp, (char *)doopt, option);
        nfrontp += sizeof (dont) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send do", option));
        nfrontp += sizeof (dont) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send do", option));
@@ -435,7 +466,7 @@ extern void doclientstat();
 #endif
 #ifdef ENCRYPTION
 extern void encrypt_send_support();
 #endif
 #ifdef ENCRYPTION
 extern void encrypt_send_support();
-#endif
+#endif /* ENCRYPTION */
 
        void
 willoption(option)
 
        void
 willoption(option)
@@ -524,7 +555,8 @@ willoption(option)
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_XDISPLOC:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_XDISPLOC:
-               case TELOPT_ENVIRON:
+               case TELOPT_NEW_ENVIRON:
+               case TELOPT_OLD_ENVIRON:
                        changeok++;
                        break;
 
                        changeok++;
                        break;
 
@@ -553,7 +585,7 @@ willoption(option)
                        func = encrypt_send_support;
                        changeok++;
                        break;
                        func = encrypt_send_support;
                        changeok++;
                        break;
-#endif
+#endif /* ENCRYPTION */
 
                default:
                        break;
 
                default:
                        break;
@@ -617,9 +649,9 @@ willoption(option)
                case TELOPT_ENCRYPT:
                        func = encrypt_send_support;
                        break;
                case TELOPT_ENCRYPT:
                        func = encrypt_send_support;
                        break;
-#endif
+#endif /* ENCRYPTION */
                case TELOPT_LFLOW:
                case TELOPT_LFLOW:
-                       func = localstat;
+                       func = flowstat;
                        break;
                }
            }
                        break;
                }
            }
@@ -640,7 +672,7 @@ send_dont(option, init)
                set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
                set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, dont, option);
+       (void) sprintf(nfrontp, (char *)dont, option);
        nfrontp += sizeof (doopt) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send dont", option));
        nfrontp += sizeof (doopt) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send dont", option));
@@ -738,7 +770,11 @@ wontoption(option)
                        settimer(xdisplocsubopt);
                        break;
 
                        settimer(xdisplocsubopt);
                        break;
 
-               case TELOPT_ENVIRON:
+               case TELOPT_OLD_ENVIRON:
+                       settimer(oenvironsubopt);
+                       break;
+
+               case TELOPT_NEW_ENVIRON:
                        settimer(environsubopt);
                        break;
 
                        settimer(environsubopt);
                        break;
 
@@ -786,7 +822,7 @@ send_will(option, init)
                set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
                set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, will, option);
+       (void) sprintf(nfrontp, (char *)will, option);
        nfrontp += sizeof (doopt) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send will", option));
        nfrontp += sizeof (doopt) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send will", option));
@@ -904,18 +940,21 @@ dooption(option)
                        /* NOT REACHED */
                        break;
 
                        /* NOT REACHED */
                        break;
 
-#if    defined(ENCRYPTION)
+#ifdef ENCRYPTION
                case TELOPT_ENCRYPT:
                        changeok++;
                        break;
                case TELOPT_ENCRYPT:
                        changeok++;
                        break;
-#endif
+#endif /* ENCRYPTION */
                case TELOPT_LINEMODE:
                case TELOPT_TTYPE:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
                case TELOPT_XDISPLOC:
                case TELOPT_LINEMODE:
                case TELOPT_TTYPE:
                case TELOPT_NAWS:
                case TELOPT_TSPEED:
                case TELOPT_LFLOW:
                case TELOPT_XDISPLOC:
-               case TELOPT_ENVIRON:
+#ifdef TELOPT_ENVIRON
+               case TELOPT_NEW_ENVIRON:
+#endif
+               case TELOPT_OLD_ENVIRON:
                default:
                        break;
                }
                default:
                        break;
                }
@@ -942,7 +981,7 @@ send_wont(option, init)
                set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
                set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, wont, option);
+       (void) sprintf(nfrontp, (char *)wont, option);
        nfrontp += sizeof (wont) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send wont", option));
        nfrontp += sizeof (wont) - 2;
 
        DIAG(TD_OPTIONS, printoption("td: send wont", option));
@@ -1033,6 +1072,14 @@ dontoption(option)
 
 }  /* end of dontoption */
 
 
 }  /* end of dontoption */
 
+#ifdef ENV_HACK
+int env_ovar = -1;
+int env_ovalue = -1;
+#else  /* ENV_HACK */
+# define env_ovar OLD_ENV_VAR
+# define env_ovalue OLD_ENV_VALUE
+#endif /* ENV_HACK */
+
 /*
  * suboption()
  *
 /*
  * suboption()
  *
@@ -1209,22 +1256,142 @@ suboption()
        break;
     }  /* end of case TELOPT_XDISPLOC */
 
        break;
     }  /* end of case TELOPT_XDISPLOC */
 
-    case TELOPT_ENVIRON: {
+#ifdef TELOPT_NEW_ENVIRON
+    case TELOPT_NEW_ENVIRON:
+#endif
+    case TELOPT_OLD_ENVIRON: {
        register int c;
        register char *cp, *varp, *valp;
 
        if (SB_EOF())
                return;
        c = SB_GET();
        register int c;
        register char *cp, *varp, *valp;
 
        if (SB_EOF())
                return;
        c = SB_GET();
-       if (c == TELQUAL_IS)
-               settimer(environsubopt);
-       else if (c != TELQUAL_INFO)
+       if (c == TELQUAL_IS) {
+               if (subchar == TELOPT_OLD_ENVIRON)
+                       settimer(oenvironsubopt);
+               else
+                       settimer(environsubopt);
+       } else if (c != TELQUAL_INFO) {
                return;
                return;
+       }
 
 
-       while (!SB_EOF()) {
+#ifdef TELOPT_NEW_ENVIRON
+       if (subchar == TELOPT_NEW_ENVIRON) {
+           while (!SB_EOF()) {
                c = SB_GET();
                c = SB_GET();
-               if ((c == ENV_VAR) || (c == ENV_USERVAR))
+               if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
                        break;
                        break;
+           }
+       } else
+#endif
+       {
+#ifdef ENV_HACK
+           /*
+            * We only want to do this if we haven't already decided
+            * whether or not the other side has its VALUE and VAR
+            * reversed.
+            */
+           if (env_ovar < 0) {
+               register int last = -1;         /* invalid value */
+               int empty = 0;
+               int got_var = 0, got_value = 0, got_uservar = 0;
+
+               /*
+                * The other side might have its VALUE and VAR values
+                * reversed.  To be interoperable, we need to determine
+                * which way it is.  If the first recognized character
+                * is a VAR or VALUE, then that will tell us what
+                * type of client it is.  If the fist recognized
+                * character is a USERVAR, then we continue scanning
+                * the suboption looking for two consecutive
+                * VAR or VALUE fields.  We should not get two
+                * consecutive VALUE fields, so finding two
+                * consecutive VALUE or VAR fields will tell us
+                * what the client is.
+                */
+               SB_SAVE();
+               while (!SB_EOF()) {
+                       c = SB_GET();
+                       switch(c) {
+                       case OLD_ENV_VAR:
+                               if (last < 0 || last == OLD_ENV_VAR
+                                   || (empty && (last == OLD_ENV_VALUE)))
+                                       goto env_ovar_ok;
+                               got_var++;
+                               last = OLD_ENV_VAR;
+                               break;
+                       case OLD_ENV_VALUE:
+                               if (last < 0 || last == OLD_ENV_VALUE
+                                   || (empty && (last == OLD_ENV_VAR)))
+                                       goto env_ovar_wrong;
+                               got_value++;
+                               last = OLD_ENV_VALUE;
+                               break;
+                       case ENV_USERVAR:
+                               /* count strings of USERVAR as one */
+                               if (last != ENV_USERVAR)
+                                       got_uservar++;
+                               if (empty) {
+                                       if (last == OLD_ENV_VALUE)
+                                               goto env_ovar_ok;
+                                       if (last == OLD_ENV_VAR)
+                                               goto env_ovar_wrong;
+                               }
+                               last = ENV_USERVAR;
+                               break;
+                       case ENV_ESC:
+                               if (!SB_EOF())
+                                       c = SB_GET();
+                               /* FALL THROUGH */
+                       default:
+                               empty = 0;
+                               continue;
+                       }
+                       empty = 1;
+               }
+               if (empty) {
+                       if (last == OLD_ENV_VALUE)
+                               goto env_ovar_ok;
+                       if (last == OLD_ENV_VAR)
+                               goto env_ovar_wrong;
+               }
+               /*
+                * Ok, the first thing was a USERVAR, and there
+                * are not two consecutive VAR or VALUE commands,
+                * and none of the VAR or VALUE commands are empty.
+                * If the client has sent us a well-formed option,
+                * then the number of VALUEs received should always
+                * be less than or equal to the number of VARs and
+                * USERVARs received.
+                *
+                * If we got exactly as many VALUEs as VARs and
+                * USERVARs, the client has the same definitions.
+                *
+                * If we got exactly as many VARs as VALUEs and
+                * USERVARS, the client has reversed definitions.
+                */
+               if (got_uservar + got_var == got_value) {
+           env_ovar_ok:
+                       env_ovar = OLD_ENV_VAR;
+                       env_ovalue = OLD_ENV_VALUE;
+               } else if (got_uservar + got_value == got_var) {
+           env_ovar_wrong:
+                       env_ovar = OLD_ENV_VALUE;
+                       env_ovalue = OLD_ENV_VAR;
+                       DIAG(TD_OPTIONS, {sprintf(nfrontp,
+                               "ENVIRON VALUE and VAR are reversed!\r\n");
+                               nfrontp += strlen(nfrontp);});
+
+               }
+           }
+           SB_RESTORE();
+#endif
+
+           while (!SB_EOF()) {
+               c = SB_GET();
+               if ((c == env_ovar) || (c == ENV_USERVAR))
+                       break;
+           }
        }
 
        if (SB_EOF())
        }
 
        if (SB_EOF())
@@ -1234,13 +1401,21 @@ suboption()
        valp = 0;
 
        while (!SB_EOF()) {
        valp = 0;
 
        while (!SB_EOF()) {
-               switch (c = SB_GET()) {
-               case ENV_VALUE:
+               c = SB_GET();
+               if (subchar == TELOPT_OLD_ENVIRON) {
+                       if (c == env_ovar)
+                               c = NEW_ENV_VAR;
+                       else if (c == env_ovalue)
+                               c = NEW_ENV_VALUE;
+               }
+               switch (c) {
+
+               case NEW_ENV_VALUE:
                        *cp = '\0';
                        cp = valp = (char *)subpointer;
                        break;
 
                        *cp = '\0';
                        cp = valp = (char *)subpointer;
                        break;
 
-               case ENV_VAR:
+               case NEW_ENV_VAR:
                case ENV_USERVAR:
                        *cp = '\0';
                        if (valp)
                case ENV_USERVAR:
                        *cp = '\0';
                        if (valp)
@@ -1267,7 +1442,7 @@ suboption()
        else
                unsetenv(varp);
        break;
        else
                unsetenv(varp);
        break;
-    }  /* end of case TELOPT_ENVIRON */
+    }  /* end of case TELOPT_NEW_ENVIRON */
 #if    defined(AUTHENTICATION)
     case TELOPT_AUTHENTICATION:
        if (SB_EOF())
 #if    defined(AUTHENTICATION)
     case TELOPT_AUTHENTICATION:
        if (SB_EOF())
@@ -1289,7 +1464,7 @@ suboption()
        }
        break;
 #endif
        }
        break;
 #endif
-#if    defined(ENCRYPTION)
+#ifdef ENCRYPTION
     case TELOPT_ENCRYPT:
        if (SB_EOF())
                break;
     case TELOPT_ENCRYPT:
        if (SB_EOF())
                break;
@@ -1331,7 +1506,7 @@ suboption()
                break;
        }
        break;
                break;
        }
        break;
-#endif
+#endif /* ENCRYPTION */
 
     default:
        break;
 
     default:
        break;
@@ -1371,7 +1546,7 @@ send_status()
         * WILL/DO, and the "want_state" will be WONT/DONT.  We
         * need to go by the latter.
         */
         * WILL/DO, and the "want_state" will be WONT/DONT.  We
         * need to go by the latter.
         */
-       for (i = 0; i < NTELOPTS; i++) {
+       for (i = 0; i < (unsigned char)NTELOPTS; i++) {
                if (my_want_state_is_will(i)) {
                        ADD(WILL);
                        ADD_DATA(i);
                if (my_want_state_is_will(i)) {
                        ADD(WILL);
                        ADD_DATA(i);