home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / netkit-b.05 / netkit-b / NetKit-B-0.05 / telnetd / utility.c < prev   
Encoding:
C/C++ Source or Header  |  1994-06-11  |  28.0 KB  |  1,244 lines

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