home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / telnetd / utility.c < prev   
C/C++ Source or Header  |  1996-09-28  |  28KB  |  1,197 lines

  1. /*
  2.  * Copyright (c) 1989, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)utility.c    8.4 (Berkeley) 5/30/95";
  36. #endif /* not lint */
  37.  
  38. #ifdef HAVE_CONFIG_H
  39. #include <config.h>
  40. #endif
  41.  
  42. #define PRINTOPTIONS
  43. #include "telnetd.h"
  44.  
  45. /*
  46.  * utility functions performing io related tasks
  47.  */
  48.  
  49. /*
  50.  * ttloop
  51.  *
  52.  *    A small subroutine to flush the network output buffer, get some data
  53.  * from the network, and pass it through the telnet state machine.  We
  54.  * also flush the pty input buffer (by dropping its data) if it becomes
  55.  * too full.
  56.  */
  57.  
  58.     void
  59. ttloop()
  60. {
  61.     void netflush();
  62.  
  63.     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
  64.              nfrontp += strlen(nfrontp);});
  65.     if (nfrontp-nbackp) {
  66.     netflush();
  67.     }
  68.     ncc = read(net, netibuf, sizeof netibuf);
  69.     if (ncc < 0) {
  70.     syslog(LOG_INFO, "ttloop:  read: %m\n");
  71.     exit(1);
  72.     } else if (ncc == 0) {
  73.     syslog(LOG_INFO, "ttloop:  peer died: %m\n");
  74.     exit(1);
  75.     }
  76.     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
  77.              nfrontp += strlen(nfrontp);});
  78.     netip = netibuf;
  79.     telrcv();            /* state machine */
  80.     if (ncc > 0) {
  81.     pfrontp = pbackp = ptyobuf;
  82.     telrcv();
  83.     }
  84. }  /* end of ttloop */
  85.  
  86. /*
  87.  * Check a descriptor to see if out of band data exists on it.
  88.  */
  89.     int
  90. stilloob(s)
  91.     int    s;        /* socket number */
  92. {
  93.     static struct timeval timeout = { 0 };
  94.     fd_set    excepts;
  95.     int value;
  96.  
  97.     do {
  98.     FD_ZERO(&excepts);
  99.     FD_SET(s, &excepts);
  100.     value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
  101.     } while ((value == -1) && (errno == EINTR));
  102.  
  103.     if (value < 0) {
  104.     fatalperror(pty, "select");
  105.     }
  106.     if (FD_ISSET(s, &excepts)) {
  107.     return 1;
  108.     } else {
  109.     return 0;
  110.     }
  111. }
  112.  
  113.     void
  114. ptyflush()
  115. {
  116.     int n;
  117.  
  118.     if ((n = pfrontp - pbackp) > 0) {
  119.         DIAG((TD_REPORT | TD_PTYDATA),
  120.             { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
  121.               nfrontp += strlen(nfrontp); });
  122.         DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
  123.         n = write(pty, pbackp, n);
  124.     }
  125.     if (n < 0) {
  126.         if (errno == EWOULDBLOCK || errno == EINTR)
  127.             return;
  128.         cleanup(0);
  129.     }
  130.     pbackp += n;
  131.     if (pbackp == pfrontp)
  132.         pbackp = pfrontp = ptyobuf;
  133. }
  134.  
  135. /*
  136.  * nextitem()
  137.  *
  138.  *    Return the address of the next "item" in the TELNET data
  139.  * stream.  This will be the address of the next character if
  140.  * the current address is a user data character, or it will
  141.  * be the address of the character following the TELNET command
  142.  * if the current address is a TELNET IAC ("I Am a Command")
  143.  * character.
  144.  */
  145.     char *
  146. nextitem(current)
  147.     char    *current;
  148. {
  149.     if ((*current&0xff) != IAC) {
  150.     return current+1;
  151.     }
  152.     switch (*(current+1)&0xff) {
  153.     case DO:
  154.     case DONT:
  155.     case WILL:
  156.     case WONT:
  157.     return current+3;
  158.     case SB:        /* loop forever looking for the SE */
  159.     {
  160.         register char *look = current+2;
  161.  
  162.         for (;;) {
  163.         if ((*look++&0xff) == IAC) {
  164.             if ((*look++&0xff) == SE) {
  165.             return look;
  166.             }
  167.         }
  168.         }
  169.     }
  170.     default:
  171.     return current+2;
  172.     }
  173. }  /* end of nextitem */
  174.  
  175.  
  176. /*
  177.  * netclear()
  178.  *
  179.  *    We are about to do a TELNET SYNCH operation.  Clear
  180.  * the path to the network.
  181.  *
  182.  *    Things are a bit tricky since we may have sent the first
  183.  * byte or so of a previous TELNET command into the network.
  184.  * So, we have to scan the network buffer from the beginning
  185.  * until we are up to where we want to be.
  186.  *
  187.  *    A side effect of what we do, just to keep things
  188.  * simple, is to clear the urgent data pointer.  The principal
  189.  * caller should be setting the urgent data pointer AFTER calling
  190.  * us in any case.
  191.  */
  192.     void
  193. netclear()
  194. {
  195.     register char *thisitem, *next;
  196.     char *good;
  197. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  198.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  199.  
  200. #ifdef    ENCRYPTION
  201.     thisitem = nclearto > netobuf ? nclearto : netobuf;
  202. #else    /* ENCRYPTION */
  203.     thisitem = netobuf;
  204. #endif    /* ENCRYPTION */
  205.  
  206.     while ((next = nextitem(thisitem)) <= nbackp) {
  207.     thisitem = next;
  208.     }
  209.  
  210.     /* Now, thisitem is first before/at boundary. */
  211.  
  212. #ifdef    ENCRYPTION
  213.     good = nclearto > netobuf ? nclearto : netobuf;
  214. #else    /* ENCRYPTION */
  215.     good = netobuf;    /* where the good bytes go */
  216. #endif    /* ENCRYPTION */
  217.  
  218.     while (nfrontp > thisitem) {
  219.     if (wewant(thisitem)) {
  220.         int length;
  221.  
  222.         next = thisitem;
  223.         do {
  224.         next = nextitem(next);
  225.         } while (wewant(next) && (nfrontp > next));
  226.         length = next-thisitem;
  227.         memmove(good, thisitem, length);
  228.         good += length;
  229.         thisitem = next;
  230.     } else {
  231.         thisitem = nextitem(thisitem);
  232.     }
  233.     }
  234.  
  235.     nbackp = netobuf;
  236.     nfrontp = good;        /* next byte to be sent */
  237.     neturg = 0;
  238. }  /* end of netclear */
  239.  
  240. /*
  241.  *  netflush
  242.  *        Send as much data as possible to the network,
  243.  *    handling requests for urgent data.
  244.  */
  245.     void
  246. netflush()
  247. {
  248.     int n;
  249.     extern int not42;
  250.  
  251.     if ((n = nfrontp - nbackp) > 0) {
  252.     DIAG(TD_REPORT,
  253.         { sprintf(nfrontp, "td: netflush %d chars\r\n", n);
  254.           n += strlen(nfrontp);  /* get count first */
  255.           nfrontp += strlen(nfrontp);  /* then move pointer */
  256.         });
  257. #ifdef    ENCRYPTION
  258.     if (encrypt_output) {
  259.         char *s = nclearto ? nclearto : nbackp;
  260.         if (nfrontp - s > 0) {
  261.             (*encrypt_output)((unsigned char *)s, nfrontp-s);
  262.             nclearto = nfrontp;
  263.         }
  264.     }
  265. #endif    /* ENCRYPTION */
  266.     /*
  267.      * if no urgent data, or if the other side appears to be an
  268.      * old 4.2 client (and thus unable to survive TCP urgent data),
  269.      * write the entire buffer in non-OOB mode.
  270.      */
  271.     if ((neturg == 0) || (not42 == 0)) {
  272.         n = write(net, nbackp, n);    /* normal write */
  273.     } else {
  274.         n = neturg - nbackp;
  275.         /*
  276.          * In 4.2 (and 4.3) systems, there is some question about
  277.          * what byte in a sendOOB operation is the "OOB" data.
  278.          * To make ourselves compatible, we only send ONE byte
  279.          * out of band, the one WE THINK should be OOB (though
  280.          * we really have more the TCP philosophy of urgent data
  281.          * rather than the Unix philosophy of OOB data).
  282.          */
  283.         if (n > 1) {
  284.         n = send(net, nbackp, n-1, 0);    /* send URGENT all by itself */
  285.         } else {
  286.         n = send(net, nbackp, n, MSG_OOB);    /* URGENT data */
  287.         }
  288.     }
  289.     }
  290.     if (n < 0) {
  291.     if (errno == EWOULDBLOCK || errno == EINTR)
  292.         return;
  293.     cleanup(0);
  294.     }
  295.     nbackp += n;
  296. #ifdef    ENCRYPTION
  297.     if (nbackp > nclearto)
  298.     nclearto = 0;
  299. #endif    /* ENCRYPTION */
  300.     if (nbackp >= neturg) {
  301.     neturg = 0;
  302.     }
  303.     if (nbackp == nfrontp) {
  304.     nbackp = nfrontp = netobuf;
  305. #ifdef    ENCRYPTION
  306.     nclearto = 0;
  307. #endif    /* ENCRYPTION */
  308.     }
  309.     return;
  310. }  /* end of netflush */
  311.  
  312.  
  313. /*
  314.  * writenet
  315.  *
  316.  * Just a handy little function to write a bit of raw data to the net.
  317.  * It will force a transmit of the buffer if necessary
  318.  *
  319.  * arguments
  320.  *    ptr - A pointer to a character string to write
  321.  *    len - How many bytes to write
  322.  */
  323.     void
  324. writenet(ptr, len)
  325.     register unsigned char *ptr;
  326.     register int len;
  327. {
  328.     /* flush buffer if no room for new data) */
  329.     if ((&netobuf[BUFSIZ] - nfrontp) < len) {
  330.         /* if this fails, don't worry, buffer is a little big */
  331.         netflush();
  332.     }
  333.  
  334.     memmove(nfrontp, ptr, len);
  335.     nfrontp += len;
  336.  
  337. }  /* end of writenet */
  338.  
  339.  
  340. /*
  341.  * miscellaneous functions doing a variety of little jobs follow ...
  342.  */
  343.  
  344.  
  345.     void
  346. fatal(f, msg)
  347.     int f;
  348.     char *msg;
  349. {
  350.     char buf[BUFSIZ];
  351.  
  352.     (void) sprintf(buf, "telnetd: %s.\r\n", msg);
  353. #ifdef    ENCRYPTION
  354.     if (encrypt_output) {
  355.         /*
  356.          * Better turn off encryption first....
  357.          * Hope it flushes...
  358.          */
  359.         encrypt_send_end();
  360.         netflush();
  361.     }
  362. #endif    /* ENCRYPTION */
  363.     (void) write(f, buf, (int)strlen(buf));
  364.     sleep(1);    /*XXX*/
  365.     exit(1);
  366. }
  367.  
  368.     void
  369. fatalperror(f, msg)
  370.     int f;
  371.     char *msg;
  372. {
  373.     char buf[BUFSIZ], *strerror();
  374.  
  375.     (void) sprintf(buf, "%s: %s", msg, strerror(errno));
  376.     fatal(f, buf);
  377. }
  378.  
  379. char editedhost[32];
  380.  
  381.     void
  382. edithost(pat, host)
  383.     register char *pat;
  384.     register char *host;
  385. {
  386.     register char *res = editedhost;
  387.     char *strncpy();
  388.  
  389.     if (!pat)
  390.         pat = "";
  391.     while (*pat) {
  392.         switch (*pat) {
  393.  
  394.         case '#':
  395.             if (*host)
  396.                 host++;
  397.             break;
  398.  
  399.         case '@':
  400.             if (*host)
  401.                 *res++ = *host++;
  402.             break;
  403.  
  404.         default:
  405.             *res++ = *pat;
  406.             break;
  407.         }
  408.         if (res == &editedhost[sizeof editedhost - 1]) {
  409.             *res = '\0';
  410.             return;
  411.         }
  412.         pat++;
  413.     }
  414.     if (*host)
  415.         (void) strncpy(res, host,
  416.                 sizeof editedhost - (res - editedhost) -1);
  417.     else
  418.         *res = '\0';
  419.     editedhost[sizeof editedhost - 1] = '\0';
  420. }
  421.  
  422. static char *putlocation;
  423.  
  424.     void
  425. putstr(s)
  426.     register char *s;
  427. {
  428.  
  429.     while (*s)
  430.         putchr(*s++);
  431. }
  432.  
  433.     void
  434. putchr(cc)
  435.     int cc;
  436. {
  437.     *putlocation++ = cc;
  438. }
  439.  
  440. /*
  441.  * This is split on two lines so that SCCS will not see the M
  442.  * between two % signs and expand it...
  443.  */
  444. static char fmtstr[] = { "%l:%M\
  445. %P on %A, %d %B %Y" };
  446.  
  447.     void
  448. putf(cp, where)
  449.     register char *cp;
  450.     char *where;
  451. {
  452.     char *slash;
  453.     time_t t;
  454.     char db[100];
  455. #ifdef    STREAMSPTY
  456.     extern char *strchr();
  457. #else
  458.     extern char *strrchr();
  459. #endif
  460.  
  461.     putlocation = where;
  462.  
  463.     while (*cp) {
  464.         if (*cp != '%') {
  465.             putchr(*cp++);
  466.             continue;
  467.         }
  468.         switch (*++cp) {
  469.  
  470.         case 't':
  471. #ifdef    STREAMSPTY
  472.             /* names are like /dev/pts/2 -- we want pts/2 */
  473.             slash = strchr(line+1, '/');
  474. #else
  475.             slash = strrchr(line, '/');
  476. #endif
  477.             if (slash == (char *) 0)
  478.                 putstr(line);
  479.             else
  480.                 putstr(&slash[1]);
  481.             break;
  482.  
  483.         case 'h':
  484.             putstr(editedhost);
  485.             break;
  486.  
  487.         case 'd':
  488.             (void)time(&t);
  489.             (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
  490.             putstr(db);
  491.             break;
  492.  
  493.         case '%':
  494.             putchr('%');
  495.             break;
  496.         }
  497.         cp++;
  498.     }
  499. }
  500.  
  501. #ifdef DIAGNOSTICS
  502. /*
  503.  * Print telnet options and commands in plain text, if possible.
  504.  */
  505.     void
  506. printoption(fmt, option)
  507.     register char *fmt;
  508.     register int option;
  509. {
  510.     if (TELOPT_OK(option))
  511.         sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
  512.     else if (TELCMD_OK(option))
  513.         sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
  514.     else
  515.         sprintf(nfrontp, "%s %d\r\n", fmt, option);
  516.     nfrontp += strlen(nfrontp);
  517.     return;
  518. }
  519.  
  520.     void
  521. printsub(direction, pointer, length)
  522.     char        direction;    /* '<' or '>' */
  523.     unsigned char    *pointer;    /* where suboption data sits */
  524.     int            length;        /* length of suboption data */
  525. {
  526.     register int i;
  527.     char buf[512];
  528.  
  529.         if (!(diagnostic & TD_OPTIONS))
  530.         return;
  531.  
  532.     if (direction) {
  533.         sprintf(nfrontp, "td: %s suboption ",
  534.                     direction == '<' ? "recv" : "send");
  535.         nfrontp += strlen(nfrontp);
  536.         if (length >= 3) {
  537.         register int j;
  538.  
  539.         i = pointer[length-2];
  540.         j = pointer[length-1];
  541.  
  542.         if (i != IAC || j != SE) {
  543.             sprintf(nfrontp, "(terminated by ");
  544.             nfrontp += strlen(nfrontp);
  545.             if (TELOPT_OK(i))
  546.             sprintf(nfrontp, "%s ", TELOPT(i));
  547.             else if (TELCMD_OK(i))
  548.             sprintf(nfrontp, "%s ", TELCMD(i));
  549.             else
  550.             sprintf(nfrontp, "%d ", i);
  551.             nfrontp += strlen(nfrontp);
  552.             if (TELOPT_OK(j))
  553.             sprintf(nfrontp, "%s", TELOPT(j));
  554.             else if (TELCMD_OK(j))
  555.             sprintf(nfrontp, "%s", TELCMD(j));
  556.             else
  557.             sprintf(nfrontp, "%d", j);
  558.             nfrontp += strlen(nfrontp);
  559.             sprintf(nfrontp, ", not IAC SE!) ");
  560.             nfrontp += strlen(nfrontp);
  561.         }
  562.         }
  563.         length -= 2;
  564.     }
  565.     if (length < 1) {
  566.         sprintf(nfrontp, "(Empty suboption??\?)");
  567.         nfrontp += strlen(nfrontp);
  568.         return;
  569.     }
  570.     switch (pointer[0]) {
  571.     case TELOPT_TTYPE:
  572.         sprintf(nfrontp, "TERMINAL-TYPE ");
  573.         nfrontp += strlen(nfrontp);
  574.         switch (pointer[1]) {
  575.         case TELQUAL_IS:
  576.         sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
  577.         break;
  578.         case TELQUAL_SEND:
  579.         sprintf(nfrontp, "SEND");
  580.         break;
  581.         default:
  582.         sprintf(nfrontp,
  583.                 "- unknown qualifier %d (0x%x).",
  584.                 pointer[1], pointer[1]);
  585.         }
  586.         nfrontp += strlen(nfrontp);
  587.         break;
  588.     case TELOPT_TSPEED:
  589.         sprintf(nfrontp, "TERMINAL-SPEED");
  590.         nfrontp += strlen(nfrontp);
  591.         if (length < 2) {
  592.         sprintf(nfrontp, " (empty suboption??\?)");
  593.         nfrontp += strlen(nfrontp);
  594.         break;
  595.         }
  596.         switch (pointer[1]) {
  597.         case TELQUAL_IS:
  598.         sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
  599.         nfrontp += strlen(nfrontp);
  600.         break;
  601.         default:
  602.         if (pointer[1] == 1)
  603.             sprintf(nfrontp, " SEND");
  604.         else
  605.             sprintf(nfrontp, " %d (unknown)", pointer[1]);
  606.         nfrontp += strlen(nfrontp);
  607.         for (i = 2; i < length; i++) {
  608.             sprintf(nfrontp, " ?%d?", pointer[i]);
  609.             nfrontp += strlen(nfrontp);
  610.         }
  611.         break;
  612.         }
  613.         break;
  614.  
  615.     case TELOPT_LFLOW:
  616.         sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
  617.         nfrontp += strlen(nfrontp);
  618.         if (length < 2) {
  619.         sprintf(nfrontp, " (empty suboption??\?)");
  620.         nfrontp += strlen(nfrontp);
  621.         break;
  622.         }
  623.         switch (pointer[1]) {
  624.         case LFLOW_OFF:
  625.         sprintf(nfrontp, " OFF"); break;
  626.         case LFLOW_ON:
  627.         sprintf(nfrontp, " ON"); break;
  628.         case LFLOW_RESTART_ANY:
  629.         sprintf(nfrontp, " RESTART-ANY"); break;
  630.         case LFLOW_RESTART_XON:
  631.         sprintf(nfrontp, " RESTART-XON"); break;
  632.         default:
  633.         sprintf(nfrontp, " %d (unknown)", pointer[1]);
  634.         }
  635.         nfrontp += strlen(nfrontp);
  636.         for (i = 2; i < length; i++) {
  637.         sprintf(nfrontp, " ?%d?", pointer[i]);
  638.         nfrontp += strlen(nfrontp);
  639.         }
  640.         break;
  641.  
  642.     case TELOPT_NAWS:
  643.         sprintf(nfrontp, "NAWS");
  644.         nfrontp += strlen(nfrontp);
  645.         if (length < 2) {
  646.         sprintf(nfrontp, " (empty suboption??\?)");
  647.         nfrontp += strlen(nfrontp);
  648.         break;
  649.         }
  650.         if (length == 2) {
  651.         sprintf(nfrontp, " ?%d?", pointer[1]);
  652.         nfrontp += strlen(nfrontp);
  653.         break;
  654.         }
  655.         sprintf(nfrontp, " %d %d (%d)",
  656.         pointer[1], pointer[2],
  657.         (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
  658.         nfrontp += strlen(nfrontp);
  659.         if (length == 4) {
  660.         sprintf(nfrontp, " ?%d?", pointer[3]);
  661.         nfrontp += strlen(nfrontp);
  662.         break;
  663.         }
  664.         sprintf(nfrontp, " %d %d (%d)",
  665.         pointer[3], pointer[4],
  666.         (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
  667.         nfrontp += strlen(nfrontp);
  668.         for (i = 5; i < length; i++) {
  669.         sprintf(nfrontp, " ?%d?", pointer[i]);
  670.         nfrontp += strlen(nfrontp);
  671.         }
  672.         break;
  673.  
  674.     case TELOPT_LINEMODE:
  675.         sprintf(nfrontp, "LINEMODE ");
  676.         nfrontp += strlen(nfrontp);
  677.         if (length < 2) {
  678.         sprintf(nfrontp, " (empty suboption??\?)");
  679.         nfrontp += strlen(nfrontp);
  680.         break;
  681.         }
  682.         switch (pointer[1]) {
  683.         case WILL:
  684.         sprintf(nfrontp, "WILL ");
  685.         goto common;
  686.         case WONT:
  687.         sprintf(nfrontp, "WONT ");
  688.         goto common;
  689.         case DO:
  690.         sprintf(nfrontp, "DO ");
  691.         goto common;
  692.         case DONT:
  693.         sprintf(nfrontp, "DONT ");
  694.         common:
  695.         nfrontp += strlen(nfrontp);
  696.         if (length < 3) {
  697.             sprintf(nfrontp, "(no option??\?)");
  698.             nfrontp += strlen(nfrontp);
  699.             break;
  700.         }
  701.         switch (pointer[2]) {
  702.         case LM_FORWARDMASK:
  703.             sprintf(nfrontp, "Forward Mask");
  704.             nfrontp += strlen(nfrontp);
  705.             for (i = 3; i < length; i++) {
  706.             sprintf(nfrontp, " %x", pointer[i]);
  707.             nfrontp += strlen(nfrontp);
  708.             }
  709.             break;
  710.         default:
  711.             sprintf(nfrontp, "%d (unknown)", pointer[2]);
  712.             nfrontp += strlen(nfrontp);
  713.             for (i = 3; i < length; i++) {
  714.             sprintf(nfrontp, " %d", pointer[i]);
  715.             nfrontp += strlen(nfrontp);
  716.             }
  717.             break;
  718.         }
  719.         break;
  720.         
  721.         case LM_SLC:
  722.         sprintf(nfrontp, "SLC");
  723.         nfrontp += strlen(nfrontp);
  724.         for (i = 2; i < length - 2; i += 3) {
  725.             if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
  726.             sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
  727.             else
  728.             sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
  729.             nfrontp += strlen(nfrontp);
  730.             switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
  731.             case SLC_NOSUPPORT:
  732.             sprintf(nfrontp, " NOSUPPORT"); break;
  733.             case SLC_CANTCHANGE:
  734.             sprintf(nfrontp, " CANTCHANGE"); break;
  735.             case SLC_VARIABLE:
  736.             sprintf(nfrontp, " VARIABLE"); break;
  737.             case SLC_DEFAULT:
  738.             sprintf(nfrontp, " DEFAULT"); break;
  739.             }
  740.             nfrontp += strlen(nfrontp);
  741.             sprintf(nfrontp, "%s%s%s",
  742.             pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
  743.             pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
  744.             pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
  745.             nfrontp += strlen(nfrontp);
  746.             if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
  747.                         SLC_FLUSHOUT| SLC_LEVELBITS)) {
  748.             sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
  749.             nfrontp += strlen(nfrontp);
  750.             }
  751.             sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
  752.             nfrontp += strlen(nfrontp);
  753.             if ((pointer[i+SLC_VALUE] == IAC) &&
  754.             (pointer[i+SLC_VALUE+1] == IAC))
  755.                 i++;
  756.         }
  757.         for (; i < length; i++) {
  758.             sprintf(nfrontp, " ?%d?", pointer[i]);
  759.             nfrontp += strlen(nfrontp);
  760.         }
  761.         break;
  762.  
  763.         case LM_MODE:
  764.         sprintf(nfrontp, "MODE ");
  765.         nfrontp += strlen(nfrontp);
  766.         if (length < 3) {
  767.             sprintf(nfrontp, "(no mode??\?)");
  768.             nfrontp += strlen(nfrontp);
  769.             break;
  770.         }
  771.         {
  772.             char tbuf[32];
  773.             sprintf(tbuf, "%s%s%s%s%s",
  774.             pointer[2]&MODE_EDIT ? "|EDIT" : "",
  775.             pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
  776.             pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
  777.             pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
  778.             pointer[2]&MODE_ACK ? "|ACK" : "");
  779.             sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
  780.             nfrontp += strlen(nfrontp);
  781.         }
  782.         if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
  783.             sprintf(nfrontp, " (0x%x)", pointer[2]);
  784.             nfrontp += strlen(nfrontp);
  785.         }
  786.         for (i = 3; i < length; i++) {
  787.             sprintf(nfrontp, " ?0x%x?", pointer[i]);
  788.             nfrontp += strlen(nfrontp);
  789.         }
  790.         break;
  791.         default:
  792.         sprintf(nfrontp, "%d (unknown)", pointer[1]);
  793.         nfrontp += strlen(nfrontp);
  794.         for (i = 2; i < length; i++) {
  795.             sprintf(nfrontp, " %d", pointer[i]);
  796.             nfrontp += strlen(nfrontp);
  797.         }
  798.         }
  799.         break;
  800.  
  801.     case TELOPT_STATUS: {
  802.         register char *cp;
  803.         register int j, k;
  804.  
  805.         sprintf(nfrontp, "STATUS");
  806.         nfrontp += strlen(nfrontp);
  807.  
  808.         switch (pointer[1]) {
  809.         default:
  810.         if (pointer[1] == TELQUAL_SEND)
  811.             sprintf(nfrontp, " SEND");
  812.         else
  813.             sprintf(nfrontp, " %d (unknown)", pointer[1]);
  814.         nfrontp += strlen(nfrontp);
  815.         for (i = 2; i < length; i++) {
  816.             sprintf(nfrontp, " ?%d?", pointer[i]);
  817.             nfrontp += strlen(nfrontp);
  818.         }
  819.         break;
  820.         case TELQUAL_IS:
  821.         sprintf(nfrontp, " IS\r\n");
  822.         nfrontp += strlen(nfrontp);
  823.  
  824.         for (i = 2; i < length; i++) {
  825.             switch(pointer[i]) {
  826.             case DO:    cp = "DO"; goto common2;
  827.             case DONT:    cp = "DONT"; goto common2;
  828.             case WILL:    cp = "WILL"; goto common2;
  829.             case WONT:    cp = "WONT"; goto common2;
  830.             common2:
  831.             i++;
  832.             if (TELOPT_OK(pointer[i]))
  833.                 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
  834.             else
  835.                 sprintf(nfrontp, " %s %d", cp, pointer[i]);
  836.             nfrontp += strlen(nfrontp);
  837.  
  838.             sprintf(nfrontp, "\r\n");
  839.             nfrontp += strlen(nfrontp);
  840.             break;
  841.  
  842.             case SB:
  843.             sprintf(nfrontp, " SB ");
  844.             nfrontp += strlen(nfrontp);
  845.             i++;
  846.             j = k = i;
  847.             while (j < length) {
  848.                 if (pointer[j] == SE) {
  849.                 if (j+1 == length)
  850.                     break;
  851.                 if (pointer[j+1] == SE)
  852.                     j++;
  853.                 else
  854.                     break;
  855.                 }
  856.                 pointer[k++] = pointer[j++];
  857.             }
  858.             printsub(0, &pointer[i], k - i);
  859.             if (i < length) {
  860.                 sprintf(nfrontp, " SE");
  861.                 nfrontp += strlen(nfrontp);
  862.                 i = j;
  863.             } else
  864.                 i = j - 1;
  865.  
  866.             sprintf(nfrontp, "\r\n");
  867.             nfrontp += strlen(nfrontp);
  868.  
  869.             break;
  870.                 
  871.             default:
  872.             sprintf(nfrontp, " %d", pointer[i]);
  873.             nfrontp += strlen(nfrontp);
  874.             break;
  875.             }
  876.         }
  877.         break;
  878.         }
  879.         break;
  880.       }
  881.  
  882.     case TELOPT_XDISPLOC:
  883.         sprintf(nfrontp, "X-DISPLAY-LOCATION ");
  884.         nfrontp += strlen(nfrontp);
  885.         switch (pointer[1]) {
  886.         case TELQUAL_IS:
  887.         sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
  888.         break;
  889.         case TELQUAL_SEND:
  890.         sprintf(nfrontp, "SEND");
  891.         break;
  892.         default:
  893.         sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
  894.                 pointer[1], pointer[1]);
  895.         }
  896.         nfrontp += strlen(nfrontp);
  897.         break;
  898.  
  899.     case TELOPT_NEW_ENVIRON:
  900.         sprintf(nfrontp, "NEW-ENVIRON ");
  901.         goto env_common1;
  902.     case TELOPT_OLD_ENVIRON:
  903.         sprintf(nfrontp, "OLD-ENVIRON");
  904.     env_common1:
  905.         nfrontp += strlen(nfrontp);
  906.         switch (pointer[1]) {
  907.         case TELQUAL_IS:
  908.         sprintf(nfrontp, "IS ");
  909.         goto env_common;
  910.         case TELQUAL_SEND:
  911.         sprintf(nfrontp, "SEND ");
  912.         goto env_common;
  913.         case TELQUAL_INFO:
  914.         sprintf(nfrontp, "INFO ");
  915.         env_common:
  916.         nfrontp += strlen(nfrontp);
  917.         {
  918.             register int noquote = 2;
  919.             for (i = 2; i < length; i++ ) {
  920.             switch (pointer[i]) {
  921.             case NEW_ENV_VAR:
  922.                 sprintf(nfrontp, "\" VAR " + noquote);
  923.                 nfrontp += strlen(nfrontp);
  924.                 noquote = 2;
  925.                 break;
  926.  
  927.             case NEW_ENV_VALUE:
  928.                 sprintf(nfrontp, "\" VALUE " + noquote);
  929.                 nfrontp += strlen(nfrontp);
  930.                 noquote = 2;
  931.                 break;
  932.  
  933.             case ENV_ESC:
  934.                 sprintf(nfrontp, "\" ESC " + noquote);
  935.                 nfrontp += strlen(nfrontp);
  936.                 noquote = 2;
  937.                 break;
  938.  
  939.             case ENV_USERVAR:
  940.                 sprintf(nfrontp, "\" USERVAR " + noquote);
  941.                 nfrontp += strlen(nfrontp);
  942.                 noquote = 2;
  943.                 break;
  944.  
  945.             default:
  946.             def_case:
  947.                 if (isprint(pointer[i]) && pointer[i] != '"') {
  948.                 if (noquote) {
  949.                     *nfrontp++ = '"';
  950.                     noquote = 0;
  951.                 }
  952.                 *nfrontp++ = pointer[i];
  953.                 } else {
  954.                 sprintf(nfrontp, "\" %03o " + noquote,
  955.                             pointer[i]);
  956.                 nfrontp += strlen(nfrontp);
  957.                 noquote = 2;
  958.                 }
  959.                 break;
  960.             }
  961.             }
  962.             if (!noquote)
  963.             *nfrontp++ = '"';
  964.             break;
  965.         }
  966.         }
  967.         break;
  968.  
  969. #if    defined(AUTHENTICATION)
  970.     case TELOPT_AUTHENTICATION:
  971.         sprintf(nfrontp, "AUTHENTICATION");
  972.         nfrontp += strlen(nfrontp);
  973.     
  974.         if (length < 2) {
  975.         sprintf(nfrontp, " (empty suboption??\?)");
  976.         nfrontp += strlen(nfrontp);
  977.         break;
  978.         }
  979.         switch (pointer[1]) {
  980.         case TELQUAL_REPLY:
  981.         case TELQUAL_IS:
  982.         sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
  983.                             "IS" : "REPLY");
  984.         nfrontp += strlen(nfrontp);
  985.         if (AUTHTYPE_NAME_OK(pointer[2]))
  986.             sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
  987.         else
  988.             sprintf(nfrontp, "%d ", pointer[2]);
  989.         nfrontp += strlen(nfrontp);
  990.         if (length < 3) {
  991.             sprintf(nfrontp, "(partial suboption??\?)");
  992.             nfrontp += strlen(nfrontp);
  993.             break;
  994.         }
  995.         sprintf(nfrontp, "%s|%s",
  996.             ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  997.             "CLIENT" : "SERVER",
  998.             ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  999.             "MUTUAL" : "ONE-WAY");
  1000.         nfrontp += strlen(nfrontp);
  1001.  
  1002.         auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  1003.         sprintf(nfrontp, "%s", buf);
  1004.         nfrontp += strlen(nfrontp);
  1005.         break;
  1006.  
  1007.         case TELQUAL_SEND:
  1008.         i = 2;
  1009.         sprintf(nfrontp, " SEND ");
  1010.         nfrontp += strlen(nfrontp);
  1011.         while (i < length) {
  1012.             if (AUTHTYPE_NAME_OK(pointer[i]))
  1013.             sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
  1014.             else
  1015.             sprintf(nfrontp, "%d ", pointer[i]);
  1016.             nfrontp += strlen(nfrontp);
  1017.             if (++i >= length) {
  1018.             sprintf(nfrontp, "(partial suboption??\?)");
  1019.             nfrontp += strlen(nfrontp);
  1020.             break;
  1021.             }
  1022.             sprintf(nfrontp, "%s|%s ",
  1023.             ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  1024.                             "CLIENT" : "SERVER",
  1025.             ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  1026.                             "MUTUAL" : "ONE-WAY");
  1027.             nfrontp += strlen(nfrontp);
  1028.             ++i;
  1029.         }
  1030.         break;
  1031.  
  1032.         case TELQUAL_NAME:
  1033.         i = 2;
  1034.         sprintf(nfrontp, " NAME \"");
  1035.         nfrontp += strlen(nfrontp);
  1036.         while (i < length)
  1037.             *nfrontp += pointer[i++];
  1038.         *nfrontp += '"';
  1039.         break;
  1040.  
  1041.         default:
  1042.             for (i = 2; i < length; i++) {
  1043.             sprintf(nfrontp, " ?%d?", pointer[i]);
  1044.             nfrontp += strlen(nfrontp);
  1045.             }
  1046.             break;
  1047.         }
  1048.         break;
  1049. #endif
  1050.  
  1051. #ifdef    ENCRYPTION
  1052.     case TELOPT_ENCRYPT:
  1053.         sprintf(nfrontp, "ENCRYPT");
  1054.         nfrontp += strlen(nfrontp);
  1055.         if (length < 2) {
  1056.         sprintf(nfrontp, " (empty suboption??\?)");
  1057.         nfrontp += strlen(nfrontp);
  1058.         break;
  1059.         }
  1060.         switch (pointer[1]) {
  1061.         case ENCRYPT_START:
  1062.         sprintf(nfrontp, " START");
  1063.         nfrontp += strlen(nfrontp);
  1064.         break;
  1065.  
  1066.         case ENCRYPT_END:
  1067.         sprintf(nfrontp, " END");
  1068.         nfrontp += strlen(nfrontp);
  1069.         break;
  1070.  
  1071.         case ENCRYPT_REQSTART:
  1072.         sprintf(nfrontp, " REQUEST-START");
  1073.         nfrontp += strlen(nfrontp);
  1074.         break;
  1075.  
  1076.         case ENCRYPT_REQEND:
  1077.         sprintf(nfrontp, " REQUEST-END");
  1078.         nfrontp += strlen(nfrontp);
  1079.         break;
  1080.  
  1081.         case ENCRYPT_IS:
  1082.         case ENCRYPT_REPLY:
  1083.         sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
  1084.                             "IS" : "REPLY");
  1085.         nfrontp += strlen(nfrontp);
  1086.         if (length < 3) {
  1087.             sprintf(nfrontp, " (partial suboption??\?)");
  1088.             nfrontp += strlen(nfrontp);
  1089.             break;
  1090.         }
  1091.         if (ENCTYPE_NAME_OK(pointer[2]))
  1092.             sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
  1093.         else
  1094.             sprintf(nfrontp, " %d (unknown)", pointer[2]);
  1095.         nfrontp += strlen(nfrontp);
  1096.  
  1097.         encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  1098.         sprintf(nfrontp, "%s", buf);
  1099.         nfrontp += strlen(nfrontp);
  1100.         break;
  1101.  
  1102.         case ENCRYPT_SUPPORT:
  1103.         i = 2;
  1104.         sprintf(nfrontp, " SUPPORT ");
  1105.         nfrontp += strlen(nfrontp);
  1106.         while (i < length) {
  1107.             if (ENCTYPE_NAME_OK(pointer[i]))
  1108.             sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
  1109.             else
  1110.             sprintf(nfrontp, "%d ", pointer[i]);
  1111.             nfrontp += strlen(nfrontp);
  1112.             i++;
  1113.         }
  1114.         break;
  1115.  
  1116.         case ENCRYPT_ENC_KEYID:
  1117.         sprintf(nfrontp, " ENC_KEYID", pointer[1]);
  1118.         nfrontp += strlen(nfrontp);
  1119.         goto encommon;
  1120.  
  1121.         case ENCRYPT_DEC_KEYID:
  1122.         sprintf(nfrontp, " DEC_KEYID", pointer[1]);
  1123.         nfrontp += strlen(nfrontp);
  1124.         goto encommon;
  1125.  
  1126.         default:
  1127.         sprintf(nfrontp, " %d (unknown)", pointer[1]);
  1128.         nfrontp += strlen(nfrontp);
  1129.         encommon:
  1130.         for (i = 2; i < length; i++) {
  1131.             sprintf(nfrontp, " %d", pointer[i]);
  1132.             nfrontp += strlen(nfrontp);
  1133.         }
  1134.         break;
  1135.         }
  1136.         break;
  1137. #endif    /* ENCRYPTION */
  1138.  
  1139.     default:
  1140.         if (TELOPT_OK(pointer[0]))
  1141.             sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
  1142.         else
  1143.             sprintf(nfrontp, "%d (unknown)", pointer[i]);
  1144.         nfrontp += strlen(nfrontp);
  1145.         for (i = 1; i < length; i++) {
  1146.         sprintf(nfrontp, " %d", pointer[i]);
  1147.         nfrontp += strlen(nfrontp);
  1148.         }
  1149.         break;
  1150.     }
  1151.     sprintf(nfrontp, "\r\n");
  1152.     nfrontp += strlen(nfrontp);
  1153. }
  1154.  
  1155. /*
  1156.  * Dump a data buffer in hex and ascii to the output data stream.
  1157.  */
  1158.     void
  1159. printdata(tag, ptr, cnt)
  1160.     register char *tag;
  1161.     register char *ptr;
  1162.     register int cnt;
  1163. {
  1164.     register int i;
  1165.     char xbuf[30];
  1166.  
  1167.     while (cnt) {
  1168.         /* flush net output buffer if no room for new data) */
  1169.         if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
  1170.             netflush();
  1171.         }
  1172.  
  1173.         /* add a line of output */
  1174.         sprintf(nfrontp, "%s: ", tag);
  1175.         nfrontp += strlen(nfrontp);
  1176.         for (i = 0; i < 20 && cnt; i++) {
  1177.             sprintf(nfrontp, "%02x", *ptr);
  1178.             nfrontp += strlen(nfrontp); 
  1179.             if (isprint(*ptr)) {
  1180.                 xbuf[i] = *ptr;
  1181.             } else {
  1182.                 xbuf[i] = '.';
  1183.             }
  1184.             if (i % 2) { 
  1185.                 *nfrontp = ' ';
  1186.                 nfrontp++;
  1187.             }
  1188.             cnt--;
  1189.             ptr++;
  1190.         }
  1191.         xbuf[i] = '\0';
  1192.         sprintf(nfrontp, " %s\r\n", xbuf );
  1193.         nfrontp += strlen(nfrontp);
  1194.     } 
  1195. }
  1196. #endif /* DIAGNOSTICS */
  1197.