BSD 4_4 release
[unix-history] / usr / src / libexec / telnetd / utility.c
index 43e6eb7..d3b58ed 100644 (file)
@@ -1,24 +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.
  *
  *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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[] = "@(#)utility.c  5.4 (Berkeley) 6/28/90";
+static char sccsid[] = "@(#)utility.c  8.1 (Berkeley) 6/4/93";
 #endif /* not lint */
 
 #define PRINTOPTIONS
 #endif /* not lint */
 
 #define PRINTOPTIONS
@@ -37,17 +51,13 @@ static char sccsid[] = "@(#)utility.c       5.4 (Berkeley) 6/28/90";
  * too full.
  */
 
  * too full.
  */
 
-void
+    void
 ttloop()
 {
     void netflush();
 
 ttloop()
 {
     void netflush();
 
-#ifdef DIAGNOSTICS
-    if (diagnostic & TD_REPORT) {
-       sprintf(nfrontp, "td: ttloop\r\n");
-       nfrontp += strlen(nfrontp);
-    }
-#endif /* DIAGNOSTICS */
+    DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
+                    nfrontp += strlen(nfrontp);});
     if (nfrontp-nbackp) {
        netflush();
     }
     if (nfrontp-nbackp) {
        netflush();
     }
@@ -59,12 +69,8 @@ ttloop()
        syslog(LOG_INFO, "ttloop:  peer died: %m\n");
        exit(1);
     }
        syslog(LOG_INFO, "ttloop:  peer died: %m\n");
        exit(1);
     }
-#ifdef DIAGNOSTICS
-    if (diagnostic & TD_REPORT) {
-       sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
-       nfrontp += strlen(nfrontp);
-    }
-#endif /* DIAGNOSTICS */
+    DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
+                    nfrontp += strlen(nfrontp);});
     netip = netibuf;
     telrcv();                  /* state machine */
     if (ncc > 0) {
     netip = netibuf;
     telrcv();                  /* state machine */
     if (ncc > 0) {
@@ -76,8 +82,9 @@ ttloop()
 /*
  * Check a descriptor to see if out of band data exists on it.
  */
 /*
  * Check a descriptor to see if out of band data exists on it.
  */
+    int
 stilloob(s)
 stilloob(s)
-int    s;              /* socket number */
+    int        s;              /* socket number */
 {
     static struct timeval timeout = { 0 };
     fd_set     excepts;
 {
     static struct timeval timeout = { 0 };
     fd_set     excepts;
@@ -99,24 +106,23 @@ int        s;              /* socket number */
     }
 }
 
     }
 }
 
+       void
 ptyflush()
 {
        int n;
 
        if ((n = pfrontp - pbackp) > 0) {
 ptyflush()
 {
        int n;
 
        if ((n = pfrontp - pbackp) > 0) {
-#ifdef DIAGNOSTICS
-               if (diagnostic & (TD_REPORT | TD_PTYDATA)) {
-                       sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
-                       nfrontp += strlen(nfrontp);
-               }
-               if (diagnostic & TD_PTYDATA) {
-                       printdata("pd", pbackp, n);
-               }
-#endif /* DIAGNOSTICS */
+               DIAG((TD_REPORT | TD_PTYDATA),
+                       { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
+                         nfrontp += strlen(nfrontp); });
+               DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
                n = write(pty, pbackp, n);
        }
                n = write(pty, pbackp, n);
        }
-       if (n < 0)
-               return;
+       if (n < 0) {
+               if (errno == EWOULDBLOCK || errno == EINTR)
+                       return;
+               cleanup(0);
+       }
        pbackp += n;
        if (pbackp == pfrontp)
                pbackp = pfrontp = ptyobuf;
        pbackp += n;
        if (pbackp == pfrontp)
                pbackp = pfrontp = ptyobuf;
@@ -132,9 +138,9 @@ ptyflush()
  * if the current address is a TELNET IAC ("I Am a Command")
  * character.
  */
  * if the current address is a TELNET IAC ("I Am a Command")
  * character.
  */
-char *
+    char *
 nextitem(current)
 nextitem(current)
-char   *current;
+    char       *current;
 {
     if ((*current&0xff) != IAC) {
        return current+1;
 {
     if ((*current&0xff) != IAC) {
        return current+1;
@@ -179,6 +185,7 @@ char        *current;
  * caller should be setting the urgent data pointer AFTER calling
  * us in any case.
  */
  * caller should be setting the urgent data pointer AFTER calling
  * us in any case.
  */
+    void
 netclear()
 {
     register char *thisitem, *next;
 netclear()
 {
     register char *thisitem, *next;
@@ -186,7 +193,11 @@ netclear()
 #define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
 
 #define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
 
+#ifdef ENCRYPTION
+    thisitem = nclearto > netobuf ? nclearto : netobuf;
+#else  /* ENCRYPTION */
     thisitem = netobuf;
     thisitem = netobuf;
+#endif /* ENCRYPTION */
 
     while ((next = nextitem(thisitem)) <= nbackp) {
        thisitem = next;
 
     while ((next = nextitem(thisitem)) <= nbackp) {
        thisitem = next;
@@ -194,7 +205,11 @@ netclear()
 
     /* Now, thisitem is first before/at boundary. */
 
 
     /* Now, thisitem is first before/at boundary. */
 
+#ifdef ENCRYPTION
+    good = nclearto > netobuf ? nclearto : netobuf;
+#else  /* ENCRYPTION */
     good = netobuf;    /* where the good bytes go */
     good = netobuf;    /* where the good bytes go */
+#endif /* ENCRYPTION */
 
     while (nfrontp > thisitem) {
        if (wewant(thisitem)) {
 
     while (nfrontp > thisitem) {
        if (wewant(thisitem)) {
@@ -223,20 +238,27 @@ netclear()
  *             Send as much data as possible to the network,
  *     handling requests for urgent data.
  */
  *             Send as much data as possible to the network,
  *     handling requests for urgent data.
  */
-void
+    void
 netflush()
 {
     int n;
     extern int not42;
 
     if ((n = nfrontp - nbackp) > 0) {
 netflush()
 {
     int n;
     extern int not42;
 
     if ((n = nfrontp - nbackp) > 0) {
-#ifdef DIAGNOSTICS
-       if (diagnostic & TD_REPORT) {
-           sprintf(nfrontp, "td: netflush %d chars\r\n", n);
-           n += strlen(nfrontp);  /* get count first */
-           nfrontp += strlen(nfrontp);  /* then move pointer */
+       DIAG(TD_REPORT,
+           { sprintf(nfrontp, "td: netflush %d chars\r\n", n);
+             n += strlen(nfrontp);  /* get count first */
+             nfrontp += strlen(nfrontp);  /* then move pointer */
+           });
+#ifdef ENCRYPTION
+       if (encrypt_output) {
+               char *s = nclearto ? nclearto : nbackp;
+               if (nfrontp - s > 0) {
+                       (*encrypt_output)((unsigned char *)s, nfrontp-s);
+                       nclearto = nfrontp;
+               }
        }
        }
-#endif /* DIAGNOSTICS */
+#endif /* ENCRYPTION */
        /*
         * if no urgent data, or if the other side appears to be an
         * old 4.2 client (and thus unable to survive TCP urgent data),
        /*
         * if no urgent data, or if the other side appears to be an
         * old 4.2 client (and thus unable to survive TCP urgent data),
@@ -264,14 +286,21 @@ netflush()
     if (n < 0) {
        if (errno == EWOULDBLOCK || errno == EINTR)
                return;
     if (n < 0) {
        if (errno == EWOULDBLOCK || errno == EINTR)
                return;
-       cleanup();
+       cleanup(0);
     }
     nbackp += n;
     }
     nbackp += n;
+#ifdef ENCRYPTION
+    if (nbackp > nclearto)
+       nclearto = 0;
+#endif /* ENCRYPTION */
     if (nbackp >= neturg) {
        neturg = 0;
     }
     if (nbackp == nfrontp) {
        nbackp = nfrontp = netobuf;
     if (nbackp >= neturg) {
        neturg = 0;
     }
     if (nbackp == nfrontp) {
        nbackp = nfrontp = netobuf;
+#ifdef ENCRYPTION
+       nclearto = 0;
+#endif /* ENCRYPTION */
     }
     return;
 }  /* end of netflush */
     }
     return;
 }  /* end of netflush */
@@ -287,9 +316,10 @@ netflush()
  *    ptr - A pointer to a character string to write
  *    len - How many bytes to write
  */
  *    ptr - A pointer to a character string to write
  *    len - How many bytes to write
  */
+       void
 writenet(ptr, len)
 writenet(ptr, len)
-register char *ptr;
-register int len;
+       register unsigned char *ptr;
+       register int len;
 {
        /* flush buffer if no room for new data) */
        if ((&netobuf[BUFSIZ] - nfrontp) < len) {
 {
        /* flush buffer if no room for new data) */
        if ((&netobuf[BUFSIZ] - nfrontp) < len) {
@@ -308,6 +338,7 @@ register int len;
  */
 
 
  */
 
 
+       void
 fatal(f, msg)
        int f;
        char *msg;
 fatal(f, msg)
        int f;
        char *msg;
@@ -315,11 +346,22 @@ fatal(f, msg)
        char buf[BUFSIZ];
 
        (void) sprintf(buf, "telnetd: %s.\r\n", msg);
        char buf[BUFSIZ];
 
        (void) sprintf(buf, "telnetd: %s.\r\n", msg);
+#ifdef ENCRYPTION
+       if (encrypt_output) {
+               /*
+                * Better turn off encryption first....
+                * Hope it flushes...
+                */
+               encrypt_send_end();
+               netflush();
+       }
+#endif /* ENCRYPTION */
        (void) write(f, buf, (int)strlen(buf));
        sleep(1);       /*XXX*/
        exit(1);
 }
 
        (void) write(f, buf, (int)strlen(buf));
        sleep(1);       /*XXX*/
        exit(1);
 }
 
+       void
 fatalperror(f, msg)
        int f;
        char *msg;
 fatalperror(f, msg)
        int f;
        char *msg;
@@ -332,6 +374,7 @@ fatalperror(f, msg)
 
 char editedhost[32];
 
 
 char editedhost[32];
 
+       void
 edithost(pat, host)
        register char *pat;
        register char *host;
 edithost(pat, host)
        register char *pat;
        register char *host;
@@ -374,27 +417,37 @@ edithost(pat, host)
 
 static char *putlocation;
 
 
 static char *putlocation;
 
+       void
 putstr(s)
 putstr(s)
-register char *s;
+       register char *s;
 {
 
        while (*s)
                putchr(*s++);
 }
 
 {
 
        while (*s)
                putchr(*s++);
 }
 
+       void
 putchr(cc)
 putchr(cc)
+       int cc;
 {
        *putlocation++ = cc;
 }
 
 {
        *putlocation++ = cc;
 }
 
+/*
+ * This is split on two lines so that SCCS will not see the M
+ * between two % signs and expand it...
+ */
+static char fmtstr[] = { "%l:%M\
+%P on %A, %d %B %Y" };
+
+       void
 putf(cp, where)
 putf(cp, where)
-register char *cp;
-char *where;
+       register char *cp;
+       char *where;
 {
        char *slash;
 {
        char *slash;
-#ifndef        NO_GETTYTAB
-       char datebuffer[60];
-#endif /* NO_GETTYTAB */
+       time_t t;
+       char db[100];
        extern char *rindex();
 
        putlocation = where;
        extern char *rindex();
 
        putlocation = where;
@@ -407,7 +460,12 @@ char *where;
                switch (*++cp) {
 
                case 't':
                switch (*++cp) {
 
                case 't':
+#ifdef STREAMSPTY
+                       /* names are like /dev/pts/2 -- we want pts/2 */
+                       slash = index(line+1, '/');
+#else
                        slash = rindex(line, '/');
                        slash = rindex(line, '/');
+#endif
                        if (slash == (char *) 0)
                                putstr(line);
                        else
                        if (slash == (char *) 0)
                                putstr(line);
                        else
@@ -418,12 +476,11 @@ char *where;
                        putstr(editedhost);
                        break;
 
                        putstr(editedhost);
                        break;
 
-#ifndef        NO_GETTYTAB
                case 'd':
                case 'd':
-                       get_date(datebuffer);
-                       putstr(datebuffer);
+                       (void)time(&t);
+                       (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
+                       putstr(db);
                        break;
                        break;
-#endif /* NO_GETTYTAB */
 
                case '%':
                        putchr('%');
 
                case '%':
                        putchr('%');
@@ -433,31 +490,14 @@ char *where;
        }
 }
 
        }
 }
 
-/*ARGSUSED*/
-#ifdef NO_GETTYTAB
-getent(cp, name)
-char *cp, *name;
-{
-       return(0);
-}
-
-/*ARGSUSED*/
-char *
-getstr(cp, cpp)
-char *cp, **cpp;
-{
-       return(0);
-}
-#endif /* NO_GETTYTAB */
-
 #ifdef DIAGNOSTICS
 /*
  * Print telnet options and commands in plain text, if possible.
  */
 #ifdef DIAGNOSTICS
 /*
  * Print telnet options and commands in plain text, if possible.
  */
-void
+       void
 printoption(fmt, option)
 printoption(fmt, option)
-register char *fmt;
-register int option;
+       register char *fmt;
+       register int option;
 {
        if (TELOPT_OK(option))
                sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
 {
        if (TELOPT_OK(option))
                sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
@@ -469,18 +509,21 @@ register int option;
        return;
 }
 
        return;
 }
 
-char *slcnames[] = { SLC_NAMES };
-
-void
-printsub(dirp, pointer, length)
-char   *dirp;
-unsigned char  *pointer;       /* where suboption data sits */
-int    length;                 /* length of suboption data */
+    void
+printsub(direction, pointer, length)
+    char               direction;      /* '<' or '>' */
+    unsigned char      *pointer;       /* where suboption data sits */
+    int                        length;         /* length of suboption data */
 {
     register int i;
 {
     register int i;
+    char buf[512];
+
+        if (!(diagnostic & TD_OPTIONS))
+               return;
 
 
-       if (dirp) {
-           sprintf(nfrontp, "%s suboption ", dirp);
+       if (direction) {
+           sprintf(nfrontp, "td: %s suboption ",
+                                       direction == '<' ? "recv" : "send");
            nfrontp += strlen(nfrontp);
            if (length >= 3) {
                register int j;
            nfrontp += strlen(nfrontp);
            if (length >= 3) {
                register int j;
@@ -570,10 +613,14 @@ int       length;                 /* length of suboption data */
                break;
            }
            switch (pointer[1]) {
                break;
            }
            switch (pointer[1]) {
-           case 0:
+           case LFLOW_OFF:
                sprintf(nfrontp, " OFF"); break;
                sprintf(nfrontp, " OFF"); break;
-           case 1:
+           case LFLOW_ON:
                sprintf(nfrontp, " ON"); break;
                sprintf(nfrontp, " ON"); break;
+           case LFLOW_RESTART_ANY:
+               sprintf(nfrontp, " RESTART-ANY"); break;
+           case LFLOW_RESTART_XON:
+               sprintf(nfrontp, " RESTART-XON"); break;
            default:
                sprintf(nfrontp, " %d (unknown)", pointer[1]);
            }
            default:
                sprintf(nfrontp, " %d (unknown)", pointer[1]);
            }
@@ -667,8 +714,8 @@ int length;                 /* length of suboption data */
                sprintf(nfrontp, "SLC");
                nfrontp += strlen(nfrontp);
                for (i = 2; i < length - 2; i += 3) {
                sprintf(nfrontp, "SLC");
                nfrontp += strlen(nfrontp);
                for (i = 2; i < length - 2; i += 3) {
-                   if (pointer[i+SLC_FUNC] <= NSLC)
-                       sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]);
+                   if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+                       sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
                    else
                        sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
                    nfrontp += strlen(nfrontp);
                    else
                        sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
                    nfrontp += strlen(nfrontp);
@@ -774,7 +821,7 @@ int length;                 /* length of suboption data */
                    case WONT:  cp = "WONT"; goto common2;
                    common2:
                        i++;
                    case WONT:  cp = "WONT"; goto common2;
                    common2:
                        i++;
-                       if (TELOPT_OK((int)pointer[i]))
+                       if (TELOPT_OK(pointer[i]))
                            sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
                        else
                            sprintf(nfrontp, " %s %d", cp, pointer[i]);
                            sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
                        else
                            sprintf(nfrontp, " %s %d", cp, pointer[i]);
@@ -860,8 +907,6 @@ int length;                 /* length of suboption data */
                    for (i = 2; i < length; i++ ) {
                        switch (pointer[i]) {
                        case ENV_VAR:
                    for (i = 2; i < length; i++ ) {
                        switch (pointer[i]) {
                        case ENV_VAR:
-                           if (pointer[1] == TELQUAL_SEND)
-                               goto def_case;
                            sprintf(nfrontp, "\" VAR " + noquote);
                            nfrontp += strlen(nfrontp);
                            noquote = 2;
                            sprintf(nfrontp, "\" VAR " + noquote);
                            nfrontp += strlen(nfrontp);
                            noquote = 2;
@@ -879,6 +924,12 @@ int        length;                 /* length of suboption data */
                            noquote = 2;
                            break;
 
                            noquote = 2;
                            break;
 
+                       case ENV_USERVAR:
+                           sprintf(nfrontp, "\" USERVAR " + noquote);
+                           nfrontp += strlen(nfrontp);
+                           noquote = 2;
+                           break;
+
                        default:
                        def_case:
                            if (isprint(pointer[i]) && pointer[i] != '"') {
                        default:
                        def_case:
                            if (isprint(pointer[i]) && pointer[i] != '"') {
@@ -903,10 +954,183 @@ int      length;                 /* length of suboption data */
            }
            break;
 
            }
            break;
 
+#if    defined(AUTHENTICATION)
+       case TELOPT_AUTHENTICATION:
+           sprintf(nfrontp, "AUTHENTICATION");
+           nfrontp += strlen(nfrontp);
+       
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           switch (pointer[1]) {
+           case TELQUAL_REPLY:
+           case TELQUAL_IS:
+               sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
+                                                       "IS" : "REPLY");
+               nfrontp += strlen(nfrontp);
+               if (AUTHTYPE_NAME_OK(pointer[2]))
+                   sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
+               else
+                   sprintf(nfrontp, "%d ", pointer[2]);
+               nfrontp += strlen(nfrontp);
+               if (length < 3) {
+                   sprintf(nfrontp, "(partial suboption???)");
+                   nfrontp += strlen(nfrontp);
+                   break;
+               }
+               sprintf(nfrontp, "%s|%s",
+                       ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+                       "CLIENT" : "SERVER",
+                       ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+                       "MUTUAL" : "ONE-WAY");
+               nfrontp += strlen(nfrontp);
+
+               auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+               sprintf(nfrontp, "%s", buf);
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case TELQUAL_SEND:
+               i = 2;
+               sprintf(nfrontp, " SEND ");
+               nfrontp += strlen(nfrontp);
+               while (i < length) {
+                   if (AUTHTYPE_NAME_OK(pointer[i]))
+                       sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
+                   else
+                       sprintf(nfrontp, "%d ", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+                   if (++i >= length) {
+                       sprintf(nfrontp, "(partial suboption???)");
+                       nfrontp += strlen(nfrontp);
+                       break;
+                   }
+                   sprintf(nfrontp, "%s|%s ",
+                       ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+                                                       "CLIENT" : "SERVER",
+                       ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+                                                       "MUTUAL" : "ONE-WAY");
+                   nfrontp += strlen(nfrontp);
+                   ++i;
+               }
+               break;
+
+           case TELQUAL_NAME:
+               i = 2;
+               sprintf(nfrontp, " NAME \"");
+               nfrontp += strlen(nfrontp);
+               while (i < length)
+                   *nfrontp += pointer[i++];
+               *nfrontp += '"';
+               break;
+
+           default:
+                   for (i = 2; i < length; i++) {
+                       sprintf(nfrontp, " ?%d?", pointer[i]);
+                       nfrontp += strlen(nfrontp);
+                   }
+                   break;
+           }
+           break;
+#endif
+
+#ifdef ENCRYPTION
+       case TELOPT_ENCRYPT:
+           sprintf(nfrontp, "ENCRYPT");
+           nfrontp += strlen(nfrontp);
+           if (length < 2) {
+               sprintf(nfrontp, " (empty suboption???)");
+               nfrontp += strlen(nfrontp);
+               break;
+           }
+           switch (pointer[1]) {
+           case ENCRYPT_START:
+               sprintf(nfrontp, " START");
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case ENCRYPT_END:
+               sprintf(nfrontp, " END");
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case ENCRYPT_REQSTART:
+               sprintf(nfrontp, " REQUEST-START");
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case ENCRYPT_REQEND:
+               sprintf(nfrontp, " REQUEST-END");
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case ENCRYPT_IS:
+           case ENCRYPT_REPLY:
+               sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
+                                                       "IS" : "REPLY");
+               nfrontp += strlen(nfrontp);
+               if (length < 3) {
+                   sprintf(nfrontp, " (partial suboption???)");
+                   nfrontp += strlen(nfrontp);
+                   break;
+               }
+               if (ENCTYPE_NAME_OK(pointer[2]))
+                   sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
+               else
+                   sprintf(nfrontp, " %d (unknown)", pointer[2]);
+               nfrontp += strlen(nfrontp);
+
+               encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+               sprintf(nfrontp, "%s", buf);
+               nfrontp += strlen(nfrontp);
+               break;
+
+           case ENCRYPT_SUPPORT:
+               i = 2;
+               sprintf(nfrontp, " SUPPORT ");
+               nfrontp += strlen(nfrontp);
+               while (i < length) {
+                   if (ENCTYPE_NAME_OK(pointer[i]))
+                       sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
+                   else
+                       sprintf(nfrontp, "%d ", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+                   i++;
+               }
+               break;
+
+           case ENCRYPT_ENC_KEYID:
+               sprintf(nfrontp, " ENC_KEYID", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               goto encommon;
+
+           case ENCRYPT_DEC_KEYID:
+               sprintf(nfrontp, " DEC_KEYID", pointer[1]);
+               nfrontp += strlen(nfrontp);
+               goto encommon;
+
+           default:
+               sprintf(nfrontp, " %d (unknown)", pointer[1]);
+               nfrontp += strlen(nfrontp);
+           encommon:
+               for (i = 2; i < length; i++) {
+                   sprintf(nfrontp, " %d", pointer[i]);
+                   nfrontp += strlen(nfrontp);
+               }
+               break;
+           }
+           break;
+#endif /* ENCRYPTION */
+
        default:
        default:
-           sprintf(nfrontp, "Unknown option ");
+           if (TELOPT_OK(pointer[0]))
+               sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
+           else
+               sprintf(nfrontp, "%d (unknown)", pointer[i]);
            nfrontp += strlen(nfrontp);
            nfrontp += strlen(nfrontp);
-           for (i = 0; i < length; i++) {
+           for (i = 1; i < length; i++) {
                sprintf(nfrontp, " %d", pointer[i]);
                nfrontp += strlen(nfrontp);
            }
                sprintf(nfrontp, " %d", pointer[i]);
                nfrontp += strlen(nfrontp);
            }
@@ -919,14 +1143,14 @@ int      length;                 /* length of suboption data */
 /*
  * Dump a data buffer in hex and ascii to the output data stream.
  */
 /*
  * Dump a data buffer in hex and ascii to the output data stream.
  */
-void
+       void
 printdata(tag, ptr, cnt)
 printdata(tag, ptr, cnt)
-register char *tag;
-register char *ptr;
-register int cnt;
+       register char *tag;
+       register char *ptr;
+       register int cnt;
 {
 {
-register int i;
-char xbuf[30];
+       register int i;
+       char xbuf[30];
 
        while (cnt) {
                /* flush net output buffer if no room for new data) */
 
        while (cnt) {
                /* flush net output buffer if no room for new data) */
@@ -957,15 +1181,4 @@ char xbuf[30];
                nfrontp += strlen(nfrontp);
        } 
 }
                nfrontp += strlen(nfrontp);
        } 
 }
-
 #endif /* DIAGNOSTICS */
 #endif /* DIAGNOSTICS */
-
-#ifdef NO_STRERROR
-char *
-strerror(errno)
-{
-       extern char *sys_errlist[];
-
-       return(sys_errlist[errno]);
-}
-#endif