/[inetutils]/inetutils/telnetd/utility.c
ViewVC logotype

Diff of /inetutils/telnetd/utility.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by alainm, Wed Jul 19 04:08:39 2000 UTC revision 1.9 by gray, Fri Apr 5 00:02:43 2002 UTC
# Line 1  Line 1 
1  /*  /* Copyright (C) 1998,2001 Free Software Foundation, Inc.
  * Copyright (c) 1989, 1993  
  *      The Regents of the University of California.  All rights reserved.  
  *  
  * 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.  
  * 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.  
  */  
2    
3  #ifndef lint     This file is part of GNU Inetutils.
 static char sccsid[] = "@(#)utility.c   8.4 (Berkeley) 5/30/95";  
 #endif /* not lint */  
4    
5  #ifdef HAVE_CONFIG_H     GNU Inetutils is free software; you can redistribute it and/or modify
6  #include <config.h>     it under the terms of the GNU General Public License as published by
7       the Free Software Foundation; either version 2, or (at your option)
8       any later version.
9    
10       GNU Inetutils is distributed in the hope that it will be useful,
11       but WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
13       GNU General Public License for more details.
14    
15       You should have received a copy of the GNU General Public License
16       along with GNU Inetutils; see the file COPYING.  If not, write to
17       the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA. */
19    
20    #define TELOPTS
21    #define TELCMDS
22    #define SLC_NAMES
23    #include "telnetd.h"
24    #include <stdarg.h>
25    #include <termio.h>
26    
27    #if defined(AUTHENTICATION) || defined(ENCRYPTION)
28    # include <libtelnet/misc.h>
29    # define NET_ENCRYPT net_encrypt
30    #else
31    # define NET_ENCRYPT()
32  #endif  #endif
33    
34  #define PRINTOPTIONS  static char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;
35  #include "telnetd.h"  static char *neturg;    /* one past last byte of urgent data */
36    
37  /*  static char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
  * utility functions performing io related tasks  
  */  
38    
39  /*  static char netibuf[BUFSIZ], *netip;
40   * ttloop  static int ncc;
41    
42    static char ptyibuf[BUFSIZ], *ptyip;
43    static int pcc;
44    
45    int not42;
46    
47    static int
48    readstream (int p, char *ibuf, int bufsize)
49    {
50    #ifndef HAVE_STREAMSPTY
51      return read (p, ibuf, bufsize);
52    #else
53      int flags = 0;
54      int ret = 0;
55      struct termios *tsp;
56      struct termio *tp;
57      struct iocblk *ip;
58      char vstop, vstart;
59      int ixon;
60      int newflow;
61      struct  strbuf strbufc, strbufd;
62      unsigned char ctlbuf[BUFSIZ];
63      static int flowstate = -1;
64    
65      strbufc.maxlen = BUFSIZ;
66      strbufc.buf = (char *)ctlbuf;
67      strbufd.maxlen = bufsize-1;
68      strbufd.len = 0;
69      strbufd.buf = ibuf+1;
70      ibuf[0] = 0;
71    
72      ret = getmsg(p, &strbufc, &strbufd, &flags);
73      if (ret < 0)  /* error of some sort -- probably EAGAIN */
74        return -1;
75    
76      if (strbufc.len <= 0 || ctlbuf[0] == M_DATA)
77        {
78          /* data message */
79          if (strbufd.len > 0) /* real data */
80            return strbufd.len + 1;        /* count header char */
81          else
82            {
83              /* nothing there */
84              errno = EAGAIN;
85              return -1;
86            }
87        }
88    
89      /*
90       * It's a control message.  Return 1, to look at the flag we set
91       */
92    
93      switch (ctlbuf[0])
94        {
95        case M_FLUSH:
96          if (ibuf[1] & FLUSHW)
97            ibuf[0] = TIOCPKT_FLUSHWRITE;
98          return 1;
99    
100        case M_IOCTL:
101          ip = (struct iocblk *) (ibuf+1);
102    
103          switch (ip->ioc_cmd)
104            {
105            case TCSETS:
106            case TCSETSW:
107            case TCSETSF:
108              tsp = (struct termios *) (ibuf + 1 + sizeof(struct iocblk));
109              vstop = tsp->c_cc[VSTOP];
110              vstart = tsp->c_cc[VSTART];
111              ixon = tsp->c_iflag & IXON;
112              break;
113    
114            case TCSETA:
115            case TCSETAW:
116            case TCSETAF:
117              tp = (struct termio *) (ibuf + 1 + sizeof(struct iocblk));
118              vstop = tp->c_cc[VSTOP];
119              vstart = tp->c_cc[VSTART];
120              ixon = tp->c_iflag & IXON;
121              break;
122    
123            default:
124              errno = EAGAIN;
125              return -1;
126            }
127    
128          newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
129          if (newflow != flowstate)  /* it's a change */
130            {
131              flowstate = newflow;
132              ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
133              return 1;
134            }
135        }
136    
137      /* nothing worth doing anything about */
138      errno = EAGAIN;
139      return -1;
140    #endif /* HAVE_STREAMSPTY */
141    }
142    
143    /* ************************************************************************* */
144    /* Net and PTY I/O functions */
145    
146    void
147    io_setup ()
148    {
149      pfrontp = pbackp = ptyobuf;
150      nfrontp = nbackp = netobuf;
151      netip = netibuf;
152    }
153    
154    void
155    set_neturg ()
156    {
157      neturg = nfrontp - 1;
158    }
159    
160    /* net-buffers */
161    
162    void
163    net_output_byte (int c)
164    {
165      *nfrontp++ = c;
166    }
167    
168    int
169    net_output_data (const char *format,...)
170    {
171      va_list args;
172      size_t remaining, ret;
173    
174      va_start (args, format);
175      remaining = BUFSIZ - (nfrontp - netobuf);
176      /* try a netflush() if the room is too low */
177      if (strlen (format) > remaining || BUFSIZ / 4 > remaining)
178        {
179          netflush ();
180          remaining = BUFSIZ - (nfrontp - netobuf);
181        }
182      ret = vsnprintf (nfrontp, remaining, format, args);
183      nfrontp += ((ret < remaining - 1) ? ret : remaining - 1);
184      va_end (args);
185      return ret;
186    }
187    
188    int
189    net_output_datalen (const void *buf, size_t l)
190    {
191      size_t remaining;
192    
193      remaining = BUFSIZ - (nfrontp - netobuf);
194      if (remaining < l)
195        {
196          netflush ();
197          remaining = BUFSIZ - (nfrontp - netobuf);
198        }
199      if (remaining < l)
200        return -1;
201      memmove (nfrontp, buf, l);
202      nfrontp += l;
203      return (int) l;
204    }
205    
206    int
207    net_input_level ()
208    {
209      return ncc;
210    }
211    
212    int
213    net_output_level ()
214    {
215      return nfrontp - nbackp;
216    }
217    
218    int
219    net_buffer_is_full ()
220    {
221      return (&netobuf[BUFSIZ] - nfrontp) < 2;
222    }
223    
224    int
225    net_get_char (int peek)
226    {
227      if (peek)
228        return *netip;
229      else if (ncc > 0)
230        {
231          ncc--;
232          return *netip++ & 0377;
233        }
234    }
235    
236    int
237    net_read ()
238    {
239      ncc = read (net, netibuf, sizeof (netibuf));
240      if (ncc < 0 && errno == EWOULDBLOCK)
241        ncc = 0;
242      else if (ncc == 0)
243        {
244          syslog (LOG_INFO, "telnetd:  peer died");
245          cleanup(0);
246        }
247      else if (ncc > 0)
248        {
249          netip = netibuf;
250          DEBUG(debug_report,1,
251                debug_output_data ("td: netread %d chars\r\n", ncc));
252          DEBUG(debug_net_data,1,    
253                printdata("nd", netip, ncc));
254        }
255      return ncc;
256    }
257    
258    /* PTY buffer functions */
259    
260    int
261    pty_buffer_is_full ()
262    {
263      return (&ptyobuf[BUFSIZ] - pfrontp) < 2;
264    }
265    
266    void
267    pty_output_byte (int c)
268    {
269      *pfrontp++ = c;
270    }
271                
272    void
273    pty_output_datalen (const void *data, size_t len)
274    {
275      if ((&ptyobuf[BUFSIZ] - pfrontp) > len)
276        ptyflush ();
277      memcpy (pfrontp, data, len);
278      pfrontp += len;
279    }
280    
281    int
282    pty_input_level ()
283    {
284      return pcc;
285    }
286    
287    int
288    pty_output_level ()
289    {
290      return pfrontp - pbackp;
291    }
292    
293    void
294    ptyflush()
295    {
296      int n;
297      
298      if ((n = pfrontp - pbackp) > 0)
299        {
300          DEBUG(debug_report, 1,
301                debug_output_data ("td: ptyflush %d chars\r\n", n));
302          DEBUG(debug_pty_data, 1,
303                printdata("pd", pbackp, n));
304          n = write(pty, pbackp, n);
305        }
306    
307      if (n < 0)
308        {
309          if (errno == EWOULDBLOCK || errno == EINTR)
310            return;
311          cleanup(0);
312        }
313    
314      pbackp += n;
315      if (pbackp == pfrontp)
316        pbackp = pfrontp = ptyobuf;
317    }
318    
319    int
320    pty_get_char (int peek)
321    {
322      if (peek)
323        return *ptyip;
324      else if (pcc > 0)
325        {
326          pcc--;
327          return *ptyip++ & 0377;
328        }
329    }
330    
331    int
332    pty_read ()
333    {
334      pcc = readstream (pty, ptyibuf, BUFSIZ);
335      if (pcc < 0
336          && (errno == EWOULDBLOCK
337    #ifdef  EAGAIN
338              || errno == EAGAIN
339    #endif
340              || errno == EIO))
341        pcc = 0;
342      ptyip = ptyibuf;
343    
344      DEBUG(debug_report,1,
345            debug_output_data ("ptyread %d chars\r\n", pcc));
346      DEBUG(debug_pty_data,1,        
347            printdata("pty", ptyip, pcc));
348      return pcc;
349    }
350    
351    /* ************************************************************************* */
352    
353    
354    /* io_drain ()
355     *
356   *   *
357   *      A small subroutine to flush the network output buffer, get some data   *      A small subroutine to flush the network output buffer, get some data
358   * from the network, and pass it through the telnet state machine.  We   * from the network, and pass it through the telnet state machine.  We
# Line 52  static char sccsid[] = "@(#)utility.c  8. Line 361  static char sccsid[] = "@(#)utility.c  8.
361   */   */
362    
363  void  void
364  ttloop()  io_drain ()
365  {  {
366      void netflush();    DEBUG(debug_report, 1, debug_output_data("td: ttloop\r\n"));
367      if (nfrontp - nbackp > 0)
368      DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");      netflush ();
369                       nfrontp += strlen(nfrontp);});  
370      if (nfrontp-nbackp) {   again:
371          netflush();    ncc = read (net, netibuf, sizeof netibuf);
372      }    if (ncc < 0)
373      ncc = read(net, netibuf, sizeof netibuf);      {
374      if (ncc < 0) {        if (errno == EAGAIN)
375          syslog(LOG_INFO, "ttloop:  read: %m\n");          {
376          exit(1);            syslog (LOG_INFO, "ttloop: retrying");
377      } else if (ncc == 0) {            goto again;
378          syslog(LOG_INFO, "ttloop:  peer died: %m\n");          }
379          exit(1);        syslog (LOG_INFO, "ttloop:  read: %m\n");
380      }        exit (1);
381      DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);      }
382                       nfrontp += strlen(nfrontp);});    else if (ncc == 0)
383      netip = netibuf;      {
384      telrcv();                   /* state machine */        syslog (LOG_INFO, "ttloop:  peer died: %m\n");
385      if (ncc > 0) {        exit (1);
386          pfrontp = pbackp = ptyobuf;      }
387          telrcv();    DEBUG(debug_report, 1,
388            debug_output_data ("td: ttloop read %d chars\r\n", ncc));
389      netip = netibuf;
390      telrcv ();                    /* state machine */
391      if (ncc > 0)
392        {
393          pfrontp = pbackp = ptyobuf;
394          telrcv ();
395      }      }
396  }  /* end of ttloop */  }  /* end of ttloop */
397    
# Line 84  ttloop() Line 400  ttloop()
400   */   */
401  /* int  s; socket number */  /* int  s; socket number */
402  int  int
403  stilloob(int s)  stilloob (int s)
404  {  {
405      static struct timeval timeout = { 0 };    static struct timeval timeout = { 0 };
406      fd_set      excepts;    fd_set excepts;
407      int value;    int value;
408    
409      do {    do
410          FD_ZERO(&excepts);      {
411          FD_SET(s, &excepts);        FD_ZERO (&excepts);
412          value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);        FD_SET (s, &excepts);
413      } while ((value == -1) && (errno == EINTR));        value = select (s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
   
     if (value < 0) {  
         fatalperror(pty, "select");  
     }  
     if (FD_ISSET(s, &excepts)) {  
         return 1;  
     } else {  
         return 0;  
414      }      }
415  }    while (value == -1 && errno == EINTR);
416    
417  void    if (value < 0)
418  ptyflush()      fatalperror (pty, "select");
 {  
         int n;  
419    
420          if ((n = pfrontp - pbackp) > 0) {    return FD_ISSET (s, &excepts);
                 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);  
         }  
         if (n < 0) {  
                 if (errno == EWOULDBLOCK || errno == EINTR)  
                         return;  
                 cleanup(0);  
         }  
         pbackp += n;  
         if (pbackp == pfrontp)  
                 pbackp = pfrontp = ptyobuf;  
421  }  }
422    
423  /*  /*
# Line 139  ptyflush() Line 431  ptyflush()
431   * character.   * character.
432   */   */
433  char *  char *
434  nextitem(char *current)  nextitem (char *current)
435  {  {
436      if ((*current&0xff) != IAC) {    if ((*current&0xff) != IAC)
437          return current+1;      return current+1;
438      }  
439      switch (*(current+1)&0xff) {    switch (*(current+1)&0xff)
440        {
441      case DO:      case DO:
442      case DONT:      case DONT:
443      case WILL:      case WILL:
444      case WONT:      case WONT:
445          return current+3;          return current+3;
446            
447      case SB:            /* loop forever looking for the SE */      case SB:            /* loop forever looking for the SE */
448          {        {
449              register char *look = current+2;          register char *look = current+2;
450    
451              for (;;) {          for (;;)
452                  if ((*look++&0xff) == IAC) {            if ((*look++&0xff) == IAC
453                      if ((*look++&0xff) == SE) {                && (*look++&0xff) == SE)
454                          return look;              return look;
455                      }          
456                  }        default:
             }  
         }  
     default:  
457          return current+2;          return current+2;
458          }
459      }      }
460  }  /* end of nextitem */  }  /* end of nextitem */
461    
# Line 184  nextitem(char *current) Line 476  nextitem(char *current)
476   * caller should be setting the urgent data pointer AFTER calling   * caller should be setting the urgent data pointer AFTER calling
477   * us in any case.   * us in any case.
478   */   */
479    #define wewant(p) \
480      ((nfrontp > p) && ((*p&0xff) == IAC) && \
481       ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
482    
483    
484  void  void
485  netclear()  netclear ()
486  {  {
487      register char *thisitem, *next;    register char *thisitem, *next;
488      char *good;    char *good;
489  #define wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \    
                                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))  
   
490  #ifdef  ENCRYPTION  #ifdef  ENCRYPTION
491      thisitem = nclearto > netobuf ? nclearto : netobuf;    thisitem = nclearto > netobuf ? nclearto : netobuf;
492  #else   /* ENCRYPTION */  #else   /* ENCRYPTION */
493      thisitem = netobuf;    thisitem = netobuf;
494  #endif  /* ENCRYPTION */  #endif  /* ENCRYPTION */
495    
496      while ((next = nextitem(thisitem)) <= nbackp) {    while ((next = nextitem (thisitem)) <= nbackp)
497          thisitem = next;      thisitem = next;
     }  
498    
499      /* Now, thisitem is first before/at boundary. */    /* Now, thisitem is first before/at boundary. */
500    
501  #ifdef  ENCRYPTION  #ifdef  ENCRYPTION
502      good = nclearto > netobuf ? nclearto : netobuf;    good = nclearto > netobuf ? nclearto : netobuf;
503  #else   /* ENCRYPTION */  #else   /* ENCRYPTION */
504      good = netobuf;     /* where the good bytes go */    good = netobuf;       /* where the good bytes go */
505  #endif  /* ENCRYPTION */  #endif  /* ENCRYPTION */
506    
507      while (nfrontp > thisitem) {    while (nfrontp > thisitem)
508          if (wewant(thisitem)) {      {
509              int length;        if (wewant (thisitem))
510            {
511              next = thisitem;            int length;
512              do {  
513                  next = nextitem(next);            for (next = thisitem; wewant (next) && nfrontp > next;
514              } while (wewant(next) && (nfrontp > next));                 next = nextitem(next))
515              length = next-thisitem;              ;
516              memmove(good, thisitem, length);  
517              good += length;            length = next - thisitem;
518              thisitem = next;            memmove (good, thisitem, length);
519          } else {            good += length;
520              thisitem = nextitem(thisitem);            thisitem = next;
521            }
522          else
523            {
524              thisitem = nextitem (thisitem);
525          }          }
526      }      }
527    
528      nbackp = netobuf;    nbackp = netobuf;
529      nfrontp = good;             /* next byte to be sent */    nfrontp = good;               /* next byte to be sent */
530      neturg = 0;    neturg = 0;
531  }  /* end of netclear */  }  /* end of netclear */
532    
533  /*  /*
# Line 238  netclear() Line 536  netclear()
536   *      handling requests for urgent data.   *      handling requests for urgent data.
537   */   */
538  void  void
539  netflush()  netflush ()
540  {  {
541      int n;    int n;
542      extern int not42;    
543      if ((n = nfrontp - nbackp) > 0)
544      if ((n = nfrontp - nbackp) > 0) {      {
545          DIAG(TD_REPORT,        NET_ENCRYPT ()
546              { sprintf(nfrontp, "td: netflush %d chars\r\n", n);  
547                n += strlen(nfrontp);  /* get count first */        /*
548                nfrontp += strlen(nfrontp);  /* then move pointer */         * if no urgent data, or if the other side appears to be an
549              });         * old 4.2 client (and thus unable to survive TCP urgent data),
550  #ifdef  ENCRYPTION         * write the entire buffer in non-OOB mode.
551          if (encrypt_output) {         */
552                  char *s = nclearto ? nclearto : nbackp;        if (!neturg || !not42)
553                  if (nfrontp - s > 0) {          n = write (net, nbackp, n);     /* normal write */
554                          (*encrypt_output)((unsigned char *)s, nfrontp-s);        else
555                          nclearto = nfrontp;          {
556                  }            n = neturg - nbackp;
557          }            /*
558  #endif  /* ENCRYPTION */             * In 4.2 (and 4.3) systems, there is some question about
559          /*             * what byte in a sendOOB operation is the "OOB" data.
560           * if no urgent data, or if the other side appears to be an             * To make ourselves compatible, we only send ONE byte
561           * old 4.2 client (and thus unable to survive TCP urgent data),             * out of band, the one WE THINK should be OOB (though
562           * write the entire buffer in non-OOB mode.             * we really have more the TCP philosophy of urgent data
563           */             * rather than the Unix philosophy of OOB data).
564          if ((neturg == 0) || (not42 == 0)) {             */
565              n = write(net, nbackp, n);  /* normal write */            if (n > 1)
566          } else {              n = send (net, nbackp, n-1, 0);     /* send URGENT all by itself */
567              n = neturg - nbackp;            else
568              /*              n = send (net, nbackp, n, MSG_OOB); /* URGENT data */
              * In 4.2 (and 4.3) systems, there is some question about  
              * what byte in a sendOOB operation is the "OOB" data.  
              * To make ourselves compatible, we only send ONE byte  
              * out of band, the one WE THINK should be OOB (though  
              * we really have more the TCP philosophy of urgent data  
              * rather than the Unix philosophy of OOB data).  
              */  
             if (n > 1) {  
                 n = send(net, nbackp, n-1, 0);  /* send URGENT all by itself */  
             } else {  
                 n = send(net, nbackp, n, MSG_OOB);      /* URGENT data */  
             }  
569          }          }
570      }      }
571      if (n < 0) {    if (n < 0)
572          if (errno == EWOULDBLOCK || errno == EINTR)      {
573                  return;        if (errno == EWOULDBLOCK || errno == EINTR)
574          cleanup(0);          return;
575          cleanup (0);
576      }      }
577      nbackp += n;    
578      nbackp += n;
579  #ifdef  ENCRYPTION  #ifdef  ENCRYPTION
580      if (nbackp > nclearto)    if (nbackp > nclearto)
581          nclearto = 0;      nclearto = 0;
582  #endif  /* ENCRYPTION */  #endif  /* ENCRYPTION */
583      if (nbackp >= neturg) {    if (nbackp >= neturg)
584          neturg = 0;      neturg = 0;
585      }  
586      if (nbackp == nfrontp) {    if (nbackp == nfrontp)
587          nbackp = nfrontp = netobuf;      {
588          nbackp = nfrontp = netobuf;
589  #ifdef  ENCRYPTION  #ifdef  ENCRYPTION
590          nclearto = 0;        nclearto = 0;
591  #endif  /* ENCRYPTION */  #endif  /* ENCRYPTION */
592      }      }
593      return;    DEBUG(debug_report, 1,
594            debug_output_data ("td: netflush %d chars\r\n", n));
595      
596  }  /* end of netflush */  }  /* end of netflush */
597    
   
 /*  
  * writenet  
  *  
  * Just a handy little function to write a bit of raw data to the net.  
  * It will force a transmit of the buffer if necessary  
  *  
  * arguments  
  *    ptr - A pointer to a character string to write  
  *    len - How many bytes to write  
  */  
 void  
 writenet(register unsigned char * ptr, register int len)  
 {  
         /* flush buffer if no room for new data) */  
         if ((&netobuf[BUFSIZ] - nfrontp) < len) {  
                 /* if this fails, don't worry, buffer is a little big */  
                 netflush();  
         }  
   
         memmove(nfrontp, ptr, len);  
         nfrontp += len;  
   
 }  /* end of writenet */  
   
   
598  /*  /*
599   * miscellaneous functions doing a variety of little jobs follow ...   * miscellaneous functions doing a variety of little jobs follow ...
600   */   */
601    
   
602  void  void
603  fatal(int f, char *msg)  fatal (int f, char *msg)
604  {  {
605          char buf[BUFSIZ];    char buf[BUFSIZ];
606    
607          snprintf (buf, sizeof buf, "telnetd: %s.\r\n", msg);    snprintf (buf, sizeof buf, "telnetd: %s.\r\n", msg);
608  #ifdef  ENCRYPTION  #ifdef  ENCRYPTION
609          if (encrypt_output) {    if (encrypt_output)
610                  /*      {
611                   * Better turn off encryption first....        /*
612                   * Hope it flushes...         * Better turn off encryption first....
613                   */         * Hope it flushes...
614                  encrypt_send_end();         */
615                  netflush();        encrypt_send_end ();
616          }        netflush ();
617        }
618  #endif  /* ENCRYPTION */  #endif  /* ENCRYPTION */
619          (void) write(f, buf, (int)strlen(buf));    write (f, buf, (int)strlen (buf));
620          sleep(1);       /*XXX*/    sleep (1);    /*FIXME*/
621          exit(1);    exit (1);
622  }  }
623    
624  void  void
625  fatalperror(int f, char *msg)  fatalperror (int f, char *msg)
626  {  {
627          char buf[BUFSIZ];    char buf[BUFSIZ];
628    
629          snprintf (buf, sizeof buf, "%s: %s", msg, strerror(errno));    snprintf (buf, sizeof buf, "%s: %s", msg, strerror (errno));
630          fatal(f, buf);    fatal (f, buf);
631  }  }
632    
633  char editedhost[32];  /* ************************************************************************* */
634    /* Terminal determination */
635    
636  void  static unsigned char ttytype_sbbuf[] =
637  edithost(register char *pat, register char *host)  {
638      IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
639    };
640    
641    static void
642    _gettermname ()
643  {  {
644          register char *res = editedhost;    if (his_state_is_wont (TELOPT_TTYPE))
645  #ifndef strncpy      return;
646          char *strncpy();    settimer (baseline);
647      net_output_datalen (ttytype_sbbuf, sizeof ttytype_sbbuf);
648      ttloop (sequenceIs (ttypesubopt, baseline));
649    }
650    
651    /* FIXME: should be getterminaltype (char *user_name, size_t size)
652       Changes terminaltype.
653     */
654    int
655    getterminaltype (char *user_name)
656    {
657      int retval = -1;
658    
659      settimer (baseline);
660    #if defined(AUTHENTICATION)
661      /*
662       * Handle the Authentication option before we do anything else.
663       */
664      send_do (TELOPT_AUTHENTICATION, 1);
665      ttloop (his_will_wont_is_changing (TELOPT_AUTHENTICATION));
666      
667      if (his_state_is_will (TELOPT_AUTHENTICATION))
668        retval = auth_wait (user_name);
669  #endif  #endif
670    
671          if (!pat)  #ifdef  ENCRYPTION
672                  pat = "";    send_will (TELOPT_ENCRYPT, 1);
673          while (*pat) {  #endif /* ENCRYPTION */
674                  switch (*pat) {    send_do (TELOPT_TTYPE, 1);
675      send_do (TELOPT_TSPEED, 1);
676                  case '#':    send_do (TELOPT_XDISPLOC, 1);
677                          if (*host)    send_do (TELOPT_NEW_ENVIRON, 1);
678                                  host++;    send_do (TELOPT_OLD_ENVIRON, 1);
679                          break;  
680    #ifdef ENCRYPTION
681                  case '@':    ttloop (his_do_dont_is_changing (TELOPT_ENCRYPT)
682                          if (*host)            || his_will_wont_is_changing (TELOPT_TTYPE)
683                                  *res++ = *host++;            || his_will_wont_is_changing (TELOPT_TSPEED)
684                          break;            || his_will_wont_is_changing (TELOPT_XDISPLOC)
685              || his_will_wont_is_changing (TELOPT_NEW_ENVIRON)
686              || his_will_wont_is_changing (TELOPT_OLD_ENVIRON));
687    #else
688      ttloop (his_will_wont_is_changing (TELOPT_TTYPE)
689              || his_will_wont_is_changing (TELOPT_TSPEED)
690              || his_will_wont_is_changing (TELOPT_XDISPLOC)
691              || his_will_wont_is_changing (TELOPT_NEW_ENVIRON)
692              || his_will_wont_is_changing (TELOPT_OLD_ENVIRON));
693    #endif
694      
695    #ifdef  ENCRYPTION
696        if (his_state_is_will (TELOPT_ENCRYPT))
697          encrypt_wait ();
698    #endif
699    
700                  default:    if (his_state_is_will (TELOPT_TSPEED))
701                          *res++ = *pat;      {
702                          break;        static unsigned char sb[] =
703                  }        {IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE};
704                  if (res == &editedhost[sizeof editedhost - 1]) {  
705                          *res = '\0';        net_output_datalen (sb, sizeof sb);
706                          return;      }
707      if (his_state_is_will (TELOPT_XDISPLOC))
708        {
709          static unsigned char sb[] =
710          {IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE};
711    
712          net_output_datalen (sb, sizeof sb);
713        }
714      if (his_state_is_will (TELOPT_NEW_ENVIRON))
715        {
716          static unsigned char sb[] =
717          {IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE};
718    
719          net_output_datalen (sb, sizeof sb);
720        }
721      else if (his_state_is_will (TELOPT_OLD_ENVIRON))
722        {
723          static unsigned char sb[] =
724          {IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE};
725    
726          net_output_datalen (sb, sizeof sb);
727        }
728      if (his_state_is_will (TELOPT_TTYPE))
729        net_output_datalen (ttytype_sbbuf, sizeof ttytype_sbbuf);
730    
731      if (his_state_is_will (TELOPT_TSPEED))
732        ttloop (sequenceIs (tspeedsubopt, baseline));
733      if (his_state_is_will (TELOPT_XDISPLOC))
734        ttloop (sequenceIs (xdisplocsubopt, baseline));
735      if (his_state_is_will (TELOPT_NEW_ENVIRON))
736        ttloop (sequenceIs (environsubopt, baseline));
737      if (his_state_is_will (TELOPT_OLD_ENVIRON))
738        ttloop (sequenceIs (oenvironsubopt, baseline));
739    
740      if (his_state_is_will (TELOPT_TTYPE))
741        {
742          char *first = NULL, *last = NULL;
743    
744          ttloop (sequenceIs (ttypesubopt, baseline));
745          /*
746           * If the other side has already disabled the option, then
747           * we have to just go with what we (might) have already gotten.
748           */
749          if (his_state_is_will (TELOPT_TTYPE) && !terminaltypeok (terminaltype))
750            {
751              if (first)
752                free (first);
753              first = xstrdup (terminaltype);
754              for (;;)
755                {
756                  /* Save the unknown name, and request the next name. */
757                  if (last)
758                    free (last);
759                  last = xstrdup (terminaltype);
760                  _gettermname ();
761                  if (terminaltypeok (terminaltype))
762                    break;
763                  if ((strcmp (last, terminaltype) == 0)
764                      || his_state_is_wont (TELOPT_TTYPE))
765                    {
766                      /*
767                       * We've hit the end.  If this is the same as
768                       * the first name, just go with it.
769                       */
770                      if (strcmp (first, terminaltype) == 0)
771                        break;
772                      /*
773                       * Get the terminal name one more time, so that
774                       * RFC1091 compliant telnets will cycle back to
775                       * the start of the list.
776                       */
777                      _gettermname ();
778                      if (strcmp (first, terminaltype) != 0)
779                        {
780                          free (terminaltype);
781                          terminaltype = xstrdup (first);
782                        }
783                      break;
784                  }                  }
785                  pat++;              }
786          }          }
787          if (*host)        if (first)
788                  (void) strncpy(res, host,          free (first);
789                                  sizeof editedhost - (res - editedhost) -1);        if (last)
790          else          free (last);
791                  *res = '\0';      }
792          editedhost[sizeof editedhost - 1] = '\0';    return retval;
793    }              
794    
795    int
796    terminaltypeok (char *s)
797    {
798      char buf[1024];
799    
800      if (terminaltype == NULL)
801        return 1;
802    
803      if (tgetent (buf, s) == 0)
804        return 0;
805      return 1;
806  }  }
807    
 static char *putlocation;  
808    
809  void  /* ************************************************************************* */
810  putstr(register char *s)  /* Debugging support */
811    
812    static FILE *debug_fp = NULL;
813    
814    static int
815    debug_open ()
816  {  {
817      int um = umask(077);
818      if (!debug_fp)
819        debug_fp = fopen ("/tmp/telnet.debug", "a");
820      umask(um);
821      return debug_fp == NULL;
822    }
823    
824          while (*s)  static int
825                  putchr(*s++);  debug_close ()
826    {
827      if (debug_fp)
828        fclose (debug_fp);
829      debug_fp = NULL;
830  }  }
831    
832  void  void
833  putchr(int cc)  debug_output_datalen (const char *data, size_t len)
834  {  {
835          *putlocation++ = cc;    if (debug_open ())
836        return;
837      
838      fwrite (data, 1, len, debug_fp);
839      debug_close ();
840  }  }
841    
 /*  
  * 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" };  
   
842  void  void
843  putf(register char *cp, char *where)  debug_output_data (const char *fmt, ...)
844  {  {
845          char *slash;    va_list ap;
846          time_t t;    if (debug_open ())
847          char db[100];      return;
848  #ifdef  STREAMSPTY    va_start (ap, fmt);
849  #ifndef strchr    vfprintf (debug_fp, fmt, ap);
850          extern char *strchr();    va_end (ap);
851  #endif    debug_close ();
 #else  
 #ifndef strrchr  
         extern char *strrchr();  
 #endif  
 #endif  
   
         putlocation = where;  
   
         while (*cp) {  
                 if (*cp != '%') {  
                         putchr(*cp++);  
                         continue;  
                 }  
                 switch (*++cp) {  
   
                 case 't':  
 #ifdef  STREAMSPTY  
                         /* names are like /dev/pts/2 -- we want pts/2 */  
                         slash = strchr(line+1, '/');  
 #else  
                         slash = strrchr(line, '/');  
 #endif  
                         if (slash == (char *) 0)  
                                 putstr(line);  
                         else  
                                 putstr(&slash[1]);  
                         break;  
   
                 case 'h':  
                         putstr(editedhost);  
                         break;  
   
                 case 'd':  
                         (void)time(&t);  
                         (void)strftime(db, sizeof(db), fmtstr, localtime(&t));  
                         putstr(db);  
                         break;  
   
                 case '%':  
                         putchr('%');  
                         break;  
                 }  
                 cp++;  
         }  
852  }  }
853    
 #ifdef DIAGNOSTICS  
854  /*  /*
855   * Print telnet options and commands in plain text, if possible.   * Print telnet options and commands in plain text, if possible.
856   */   */
857  void  void
858  printoption(register char *fmt, register int option)  printoption(register char *fmt, register int option)
859  {  {
860          if (TELOPT_OK(option))    if (TELOPT_OK(option))
861                  sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));      debug_output_data ("%s %s\r\n", fmt, TELOPT(option));
862          else if (TELCMD_OK(option))    else if (TELCMD_OK(option))
863                  sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));      debug_output_data ("%s %s\r\n", fmt, TELCMD(option));
864          else    else
865                  sprintf(nfrontp, "%s %d\r\n", fmt, option);      debug_output_data ("%s %d\r\n", fmt, option);
         nfrontp += strlen(nfrontp);  
         return;  
866  }  }
867    
868  /* char direction; '<' or '>' */  /* char direction; '<' or '>' */
869  /* unsigned char *pointer;  where suboption data sits */  /* unsigned char *pointer;  where suboption data sits */
870  /* int  length;  length of suboption data */  /* int  length;  length of suboption data */
871  void  void
872  printsub(char direction, unsigned char *pointer, int length)  printsub(int direction, unsigned char *pointer, int length)
873  {  {
874      register int i;    register int i;
875      char buf[512];    char buf[512];
876    
877          if (!(diagnostic & TD_OPTIONS))    if (direction)
878                  return;      {
879          debug_output_data ("td: %s suboption ",
880                       direction == '<' ? "recv" : "send");
881          if (length >= 3)
882            {
883              register int j;
884    
885          if (direction) {            i = pointer[length-2];
886              sprintf(nfrontp, "td: %s suboption ",            j = pointer[length-1];
887                                          direction == '<' ? "recv" : "send");  
888              nfrontp += strlen(nfrontp);            if (i != IAC || j != SE)
889              if (length >= 3) {              {
890                  register int j;                debug_output_data ("(terminated by ");
891                  if (TELOPT_OK(i))
892                  i = pointer[length-2];                  debug_output_data ("%s ", TELOPT(i));
893                  j = pointer[length-1];                else if (TELCMD_OK(i))
894                    debug_output_data ("%s ", TELCMD(i));
895                  if (i != IAC || j != SE) {                else
896                      sprintf(nfrontp, "(terminated by ");                  debug_output_data ("%d ", i);
897                      nfrontp += strlen(nfrontp);                if (TELOPT_OK(j))
898                      if (TELOPT_OK(i))                  debug_output_data ("%s", TELOPT(j));
899                          sprintf(nfrontp, "%s ", TELOPT(i));                else if (TELCMD_OK(j))
900                      else if (TELCMD_OK(i))                  debug_output_data ("%s", TELCMD(j));
901                          sprintf(nfrontp, "%s ", TELCMD(i));                else
902                      else                  debug_output_data ("%d", j);
903                          sprintf(nfrontp, "%d ", i);                debug_output_data (", not IAC SE!) ");
                     nfrontp += strlen(nfrontp);  
                     if (TELOPT_OK(j))  
                         sprintf(nfrontp, "%s", TELOPT(j));  
                     else if (TELCMD_OK(j))  
                         sprintf(nfrontp, "%s", TELCMD(j));  
                     else  
                         sprintf(nfrontp, "%d", j);  
                     nfrontp += strlen(nfrontp);  
                     sprintf(nfrontp, ", not IAC SE!) ");  
                     nfrontp += strlen(nfrontp);  
                 }  
904              }              }
             length -= 2;  
905          }          }
906          if (length < 1) {        length -= 2;
907              sprintf(nfrontp, "(Empty suboption??\?)");      }
908              nfrontp += strlen(nfrontp);    if (length < 1)
909              return;      {
910          }        debug_output_data ("(Empty suboption??\?)");
911          switch (pointer[0]) {        return;
912          case TELOPT_TTYPE:      }
             sprintf(nfrontp, "TERMINAL-TYPE ");  
             nfrontp += strlen(nfrontp);  
             switch (pointer[1]) {  
             case TELQUAL_IS:  
                 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);  
                 break;  
             case TELQUAL_SEND:  
                 sprintf(nfrontp, "SEND");  
                 break;  
             default:  
                 sprintf(nfrontp,  
                                 "- unknown qualifier %d (0x%x).",  
                                 pointer[1], pointer[1]);  
             }  
             nfrontp += strlen(nfrontp);  
             break;  
         case TELOPT_TSPEED:  
             sprintf(nfrontp, "TERMINAL-SPEED");  
             nfrontp += strlen(nfrontp);  
             if (length < 2) {  
                 sprintf(nfrontp, " (empty suboption??\?)");  
                 nfrontp += strlen(nfrontp);  
                 break;  
             }  
             switch (pointer[1]) {  
             case TELQUAL_IS:  
                 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);  
                 nfrontp += strlen(nfrontp);  
                 break;  
             default:  
                 if (pointer[1] == 1)  
                     sprintf(nfrontp, " SEND");  
                 else  
                     sprintf(nfrontp, " %d (unknown)", pointer[1]);  
                 nfrontp += strlen(nfrontp);  
                 for (i = 2; i < length; i++) {  
                     sprintf(nfrontp, " ?%d?", pointer[i]);  
                     nfrontp += strlen(nfrontp);  
                 }  
                 break;  
             }  
             break;  
913    
914          case TELOPT_LFLOW:    switch (pointer[0])
915              sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");      {
916              nfrontp += strlen(nfrontp);      case TELOPT_TTYPE:
917              if (length < 2) {        debug_output_data ("TERMINAL-TYPE ");
918                  sprintf(nfrontp, " (empty suboption??\?)");        switch (pointer[1])
919                  nfrontp += strlen(nfrontp);          {
920                  break;          case TELQUAL_IS:
921              }            debug_output_data ("IS \"%.*s\"", length-2, (char *)pointer+2);
922              switch (pointer[1]) {            break;
923              case LFLOW_OFF:            
924                  sprintf(nfrontp, " OFF"); break;          case TELQUAL_SEND:
925              case LFLOW_ON:            debug_output_data ("SEND");
926                  sprintf(nfrontp, " ON"); break;            break;
927              case LFLOW_RESTART_ANY:            
928                  sprintf(nfrontp, " RESTART-ANY"); break;          default:
929              case LFLOW_RESTART_XON:            debug_output_data ("- unknown qualifier %d (0x%x).",
930                  sprintf(nfrontp, " RESTART-XON"); break;                         pointer[1], pointer[1]);
931              default:          }
932                  sprintf(nfrontp, " %d (unknown)", pointer[1]);        break;
             }  
             nfrontp += strlen(nfrontp);  
             for (i = 2; i < length; i++) {  
                 sprintf(nfrontp, " ?%d?", pointer[i]);  
                 nfrontp += strlen(nfrontp);  
             }  
             break;  
933    
934          case TELOPT_NAWS:      case TELOPT_TSPEED:
935              sprintf(nfrontp, "NAWS");        debug_output_data ("TERMINAL-SPEED");
936              nfrontp += strlen(nfrontp);        if (length < 2)
937              if (length < 2) {          {
938                  sprintf(nfrontp, " (empty suboption??\?)");            debug_output_data (" (empty suboption??\?)");
939                  nfrontp += strlen(nfrontp);            break;
940                  break;          }
             }  
             if (length == 2) {  
                 sprintf(nfrontp, " ?%d?", pointer[1]);  
                 nfrontp += strlen(nfrontp);  
                 break;  
             }  
             sprintf(nfrontp, " %d %d (%d)",  
                 pointer[1], pointer[2],  
                 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));  
             nfrontp += strlen(nfrontp);  
             if (length == 4) {  
                 sprintf(nfrontp, " ?%d?", pointer[3]);  
                 nfrontp += strlen(nfrontp);  
                 break;  
             }  
             sprintf(nfrontp, " %d %d (%d)",  
                 pointer[3], pointer[4],  
                 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));  
             nfrontp += strlen(nfrontp);  
             for (i = 5; i < length; i++) {  
                 sprintf(nfrontp, " ?%d?", pointer[i]);  
                 nfrontp += strlen(nfrontp);  
             }  
             break;  
941    
942          case TELOPT_LINEMODE:        switch (pointer[1])
943              sprintf(nfrontp, "LINEMODE ");          {
944              nfrontp += strlen(nfrontp);          case TELQUAL_IS:
945              if (length < 2) {            debug_output_data (" IS %.*s", length-2, (char *)pointer+2);
946                  sprintf(nfrontp, " (empty suboption??\?)");            break;
                 nfrontp += strlen(nfrontp);  
                 break;  
             }  
             switch (pointer[1]) {  
             case WILL:  
                 sprintf(nfrontp, "WILL ");  
                 goto common;  
             case WONT:  
                 sprintf(nfrontp, "WONT ");  
                 goto common;  
             case DO:  
                 sprintf(nfrontp, "DO ");  
                 goto common;  
             case DONT:  
                 sprintf(nfrontp, "DONT ");  
             common:  
                 nfrontp += strlen(nfrontp);  
                 if (length < 3) {  
                     sprintf(nfrontp, "(no option??\?)");  
                     nfrontp += strlen(nfrontp);  
                     break;  
                 }  
                 switch (pointer[2]) {  
                 case LM_FORWARDMASK:  
                     sprintf(nfrontp, "Forward Mask");  
                     nfrontp += strlen(nfrontp);  
                     for (i = 3; i < length; i++) {  
                         sprintf(nfrontp, " %x", pointer[i]);  
                         nfrontp += strlen(nfrontp);  
                     }  
                     break;  
                 default:  
                     sprintf(nfrontp, "%d (unknown)", pointer[2]);  
                     nfrontp += strlen(nfrontp);  
                     for (i = 3; i < length; i++) {  
                         sprintf(nfrontp, " %d", pointer[i]);  
                         nfrontp += strlen(nfrontp);  
                     }  
                     break;  
                 }  
                 break;  
947    
948              case LM_SLC:          default:
949                  sprintf(nfrontp, "SLC");            if (pointer[1] == 1)
950                  nfrontp += strlen(nfrontp);              debug_output_data (" SEND");
951                  for (i = 2; i < length - 2; i += 3) {            else
952                      if (SLC_NAME_OK(pointer[i+SLC_FUNC]))              debug_output_data (" %d (unknown)", pointer[1]);
953                          sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));            for (i = 2; i < length; i++) {
954                      else              debug_output_data (" ?%d?", pointer[i]);
955                          sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);            }
956                      nfrontp += strlen(nfrontp);            break;
957                      switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {          }
958                      case SLC_NOSUPPORT:        break;
                         sprintf(nfrontp, " NOSUPPORT"); break;  
                     case SLC_CANTCHANGE:  
                         sprintf(nfrontp, " CANTCHANGE"); break;  
                     case SLC_VARIABLE:  
                         sprintf(nfrontp, " VARIABLE"); break;  
                     case SLC_DEFAULT:  
                         sprintf(nfrontp, " DEFAULT"); break;  
                     }  
                     nfrontp += strlen(nfrontp);  
                     sprintf(nfrontp, "%s%s%s",  
                         pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",  
                         pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",  
                         pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");  
                     nfrontp += strlen(nfrontp);  
                     if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|  
                                                 SLC_FLUSHOUT| SLC_LEVELBITS)) {  
                         sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);  
                         nfrontp += strlen(nfrontp);  
                     }  
                     sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);  
                     nfrontp += strlen(nfrontp);  
                     if ((pointer[i+SLC_VALUE] == IAC) &&  
                         (pointer[i+SLC_VALUE+1] == IAC))  
                                 i++;  
                 }  
                 for (; i < length; i++) {  
                     sprintf(nfrontp, " ?%d?", pointer[i]);  
                     nfrontp += strlen(nfrontp);  
                 }  
                 break;  
959    
960              case LM_MODE:      case TELOPT_LFLOW:
961                  sprintf(nfrontp, "MODE ");        debug_output_data ("TOGGLE-FLOW-CONTROL");
962                  nfrontp += strlen(nfrontp);        if (length < 2)
963                  if (length < 3) {          {
964                      sprintf(nfrontp, "(no mode??\?)");            debug_output_data (" (empty suboption??\?)");
965                      nfrontp += strlen(nfrontp);            break;
966                      break;          }
                 }  
                 {  
                     char tbuf[32];  
                     sprintf(tbuf, "%s%s%s%s%s",  
                         pointer[2]&MODE_EDIT ? "|EDIT" : "",  
                         pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",  
                         pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",  
                         pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",  
                         pointer[2]&MODE_ACK ? "|ACK" : "");  
                     sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");  
                     nfrontp += strlen(nfrontp);  
                 }  
                 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {  
                     sprintf(nfrontp, " (0x%x)", pointer[2]);  
                     nfrontp += strlen(nfrontp);  
                 }  
                 for (i = 3; i < length; i++) {  
                     sprintf(nfrontp, " ?0x%x?", pointer[i]);  
                     nfrontp += strlen(nfrontp);  
                 }  
                 break;  
             default:  
                 sprintf(nfrontp, "%d (unknown)", pointer[1]);  
                 nfrontp += strlen(nfrontp);  
                 for (i = 2; i < length; i++) {  
                     sprintf(nfrontp, " %d", pointer[i]);  
                     nfrontp += strlen(nfrontp);  
                 }  
             }  
             break;  
967    
968          case TELOPT_STATUS: {        switch (pointer[1])
969              register char *cp;          {
970              register int j, k;          case LFLOW_OFF:
971              debug_output_data (" OFF");
972              break;
973              
974            case LFLOW_ON:
975              debug_output_data (" ON");
976              break;
977              
978            case LFLOW_RESTART_ANY:
979              debug_output_data (" RESTART-ANY");
980              break;
981              
982            case LFLOW_RESTART_XON:
983              debug_output_data (" RESTART-XON");
984              break;
985              
986            default:
987              debug_output_data (" %d (unknown)", pointer[1]);
988            }
989    
990          for (i = 2; i < length; i++)
991            debug_output_data (" ?%d?", pointer[i]);
992          break;
993    
994        case TELOPT_NAWS:
995          debug_output_data ("NAWS");
996          if (length < 2)
997            {
998              debug_output_data (" (empty suboption??\?)");
999              break;
1000            }
1001          if (length == 2)
1002            {
1003              debug_output_data (" ?%d?", pointer[1]);
1004              break;
1005            }
1006    
1007              sprintf(nfrontp, "STATUS");        debug_output_data (" %d %d (%d)",
1008              nfrontp += strlen(nfrontp);                     pointer[1], pointer[2],
1009                       (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
1010          if (length == 4)
1011            {
1012              debug_output_data (" ?%d?", pointer[3]);
1013              break;
1014            }
1015    
1016              switch (pointer[1]) {        debug_output_data (" %d %d (%d)",
1017                       pointer[3], pointer[4],
1018                       (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
1019          for (i = 5; i < length; i++)
1020                    debug_output_data (" ?%d?", pointer[i]);
1021          break;
1022    
1023        case TELOPT_LINEMODE:
1024          debug_output_data ("LINEMODE ");
1025          if (length < 2)
1026            {
1027              debug_output_data (" (empty suboption??\?)");
1028              break;
1029            }
1030    
1031          switch (pointer[1])
1032            {
1033            case WILL:
1034              debug_output_data ("WILL ");
1035              goto common;
1036    
1037            case WONT:
1038              debug_output_data ("WONT ");
1039              goto common;
1040    
1041            case DO:
1042              debug_output_data ("DO ");
1043              goto common;
1044    
1045            case DONT:
1046              debug_output_data ("DONT ");
1047    
1048            common:
1049              if (length < 3)
1050                {
1051                  debug_output_data ("(no option??\?)");
1052                  break;
1053                }
1054              switch (pointer[2])
1055                {
1056                case LM_FORWARDMASK:
1057                  debug_output_data ("Forward Mask");
1058                  for (i = 3; i < length; i++)
1059                    debug_output_data (" %x", pointer[i]);
1060                  break;
1061                  
1062              default:              default:
1063                  if (pointer[1] == TELQUAL_SEND)                debug_output_data ("%d (unknown)", pointer[2]);
1064                      sprintf(nfrontp, " SEND");                for (i = 3; i < length; i++)
1065                  else                  debug_output_data (" %d", pointer[i]);
1066                      sprintf(nfrontp, " %d (unknown)", pointer[1]);                break;
1067                  nfrontp += strlen(nfrontp);              }
1068                  for (i = 2; i < length; i++) {            break;
1069                      sprintf(nfrontp, " ?%d?", pointer[i]);  
1070                      nfrontp += strlen(nfrontp);          case LM_SLC:
1071                  }            debug_output_data ("SLC");
1072                  break;            for (i = 2; i < length - 2; i += 3)
1073              case TELQUAL_IS:              {
1074                  sprintf(nfrontp, " IS\r\n");                if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
1075                  nfrontp += strlen(nfrontp);                  debug_output_data (" %s", SLC_NAME(pointer[i+SLC_FUNC]));
1076                  else
1077                  for (i = 2; i < length; i++) {                  debug_output_data (" %d", pointer[i+SLC_FUNC]);
1078                      switch(pointer[i]) {                switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS)
1079                      case DO:    cp = "DO"; goto common2;                  {
1080                      case DONT:  cp = "DONT"; goto common2;                  case SLC_NOSUPPORT:
1081                      case WILL:  cp = "WILL"; goto common2;                    debug_output_data (" NOSUPPORT");
1082                      case WONT:  cp = "WONT"; goto common2;                    break;
1083                      common2:                    
1084                          i++;                  case SLC_CANTCHANGE:
1085                          if (TELOPT_OK(pointer[i]))                    debug_output_data (" CANTCHANGE");
1086                              sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));                    break;
1087                          else                    
1088                              sprintf(nfrontp, " %s %d", cp, pointer[i]);                  case SLC_VARIABLE:
1089                          nfrontp += strlen(nfrontp);                    debug_output_data (" VARIABLE");
1090                      break;
1091                          sprintf(nfrontp, "\r\n");                    
1092                          nfrontp += strlen(nfrontp);                  case SLC_DEFAULT:
1093                          break;                    debug_output_data (" DEFAULT");
1094                      break;
1095                      case SB:                  }
1096                          sprintf(nfrontp, " SB ");  
1097                          nfrontp += strlen(nfrontp);                debug_output_data ("%s%s%s",
1098                          i++;                             pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
1099                          j = k = i;                             pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
1100                          while (j < length) {                             pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
1101                              if (pointer[j] == SE) {                if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
1102                                  if (j+1 == length)                                            SLC_FLUSHOUT| SLC_LEVELBITS))
1103                                      break;                  debug_output_data ("(0x%x)", pointer[i+SLC_FLAGS]);
1104                                  if (pointer[j+1] == SE)                debug_output_data (" %d;", pointer[i+SLC_VALUE]);
1105                                      j++;  
1106                                  else                if ((pointer[i+SLC_VALUE] == IAC) &&
1107                                      break;                    (pointer[i+SLC_VALUE+1] == IAC))
1108                              }                  i++;
1109                              pointer[k++] = pointer[j++];              }
1110                          }  
1111                          printsub(0, &pointer[i], k - i);            for (; i < length; i++)
1112                          if (i < length) {              debug_output_data (" ?%d?", pointer[i]);
1113                              sprintf(nfrontp, " SE");            break;
1114                              nfrontp += strlen(nfrontp);  
1115                              i = j;          case LM_MODE:
1116                          } else            debug_output_data ("MODE ");
1117                              i = j - 1;            if (length < 3)
1118                {
1119                          sprintf(nfrontp, "\r\n");                debug_output_data ("(no mode??\?)");
1120                          nfrontp += strlen(nfrontp);                break;
1121                }
1122                          break;            {
1123                char tbuf[32];
1124                      default:              snprintf(tbuf, sizeof(tbuf), "%s%s%s%s%s",
1125                          sprintf(nfrontp, " %d", pointer[i]);                       pointer[2]&MODE_EDIT ? "|EDIT" : "",
1126                          nfrontp += strlen(nfrontp);                       pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
1127                          break;                       pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
1128                      }                       pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
1129                  }                       pointer[2]&MODE_ACK ? "|ACK" : "");
1130                  break;              debug_output_data ("%s", tbuf[1] ? &tbuf[1] : "0");
             }  
             break;  
1131            }            }
1132    
1133          case TELOPT_XDISPLOC:            if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
1134              sprintf(nfrontp, "X-DISPLAY-LOCATION ");              debug_output_data (" (0x%x)", pointer[2]);
             nfrontp += strlen(nfrontp);  
             switch (pointer[1]) {  
             case TELQUAL_IS:  
                 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);  
                 break;  
             case TELQUAL_SEND:  
                 sprintf(nfrontp, "SEND");  
                 break;  
             default:  
                 sprintf(nfrontp, "- unknown qualifier %d (0x%x).",  
                                 pointer[1], pointer[1]);  
             }  
             nfrontp += strlen(nfrontp);  
             break;  
1135    
1136          case TELOPT_NEW_ENVIRON:            for (i = 3; i < length; i++)
1137              sprintf(nfrontp, "NEW-ENVIRON ");              debug_output_data (" ?0x%x?", pointer[i]);
1138              goto env_common1;            break;
1139          case TELOPT_OLD_ENVIRON:            
1140              sprintf(nfrontp, "OLD-ENVIRON");          default:
1141          env_common1:            debug_output_data ("%d (unknown)", pointer[1]);
1142              nfrontp += strlen(nfrontp);            for (i = 2; i < length; i++)
1143              switch (pointer[1]) {              debug_output_data (" %d", pointer[i]);
1144              case TELQUAL_IS:          }
1145                  sprintf(nfrontp, "IS ");        break;
                 goto env_common;  
             case TELQUAL_SEND:  
                 sprintf(nfrontp, "SEND ");  
                 goto env_common;  
             case TELQUAL_INFO:  
                 sprintf(nfrontp, "INFO ");  
             env_common:  
                 nfrontp += strlen(nfrontp);  
                 {  
                     register int noquote = 2;  
                     for (i = 2; i < length; i++ ) {  
                         switch (pointer[i]) {  
                         case NEW_ENV_VAR:  
                             sprintf(nfrontp, "\" VAR " + noquote);  
                             nfrontp += strlen(nfrontp);  
                             noquote = 2;  
                             break;  
1146    
1147                          case NEW_ENV_VALUE:      case TELOPT_STATUS:
1148                              sprintf(nfrontp, "\" VALUE " + noquote);        {
1149                              nfrontp += strlen(nfrontp);          register char *cp;
1150                              noquote = 2;          register int j, k;
                             break;  
1151    
1152                          case ENV_ESC:          debug_output_data ("STATUS");
                             sprintf(nfrontp, "\" ESC " + noquote);  
                             nfrontp += strlen(nfrontp);  
                             noquote = 2;  
                             break;  
1153    
1154                          case ENV_USERVAR:          switch (pointer[1]) {
1155                              sprintf(nfrontp, "\" USERVAR " + noquote);          default:
1156                              nfrontp += strlen(nfrontp);            if (pointer[1] == TELQUAL_SEND)
1157                              noquote = 2;              debug_output_data (" SEND");
1158              else
1159                debug_output_data (" %d (unknown)", pointer[1]);
1160              for (i = 2; i < length; i++)
1161                debug_output_data (" ?%d?", pointer[i]);
1162              break;
1163              
1164            case TELQUAL_IS:
1165              debug_output_data (" IS\r\n");
1166    
1167              for (i = 2; i < length; i++)
1168                {
1169                  switch(pointer[i])
1170                    {
1171                    case DO:
1172                      cp = "DO";
1173                      goto common2;
1174    
1175                    case DONT:
1176                      cp = "DONT";
1177                      goto common2;
1178    
1179                    case WILL:
1180                      cp = "WILL";
1181                      goto common2;
1182    
1183                    case WONT:
1184                      cp = "WONT";
1185                      goto common2;
1186    
1187                    common2:
1188                      i++;
1189                      if (TELOPT_OK(pointer[i]))
1190                        debug_output_data (" %s %s\r\n", cp, TELOPT(pointer[i]));
1191                      else
1192                        debug_output_data (" %s %d\r\n", cp, pointer[i]);
1193                      break;
1194    
1195                    case SB:
1196                      debug_output_data (" SB ");
1197                      i++;
1198                      j = k = i;
1199                      while (j < length)
1200                        {
1201                          if (pointer[j] == SE)
1202                            {
1203                              if (j+1 == length)
1204                              break;                              break;
1205                              if (pointer[j+1] == SE)
1206                          default:                              j++;
1207                          def_case:                            else
                             if (isprint(pointer[i]) && pointer[i] != '"') {  
                                 if (noquote) {  
                                     *nfrontp++ = '"';  
                                     noquote = 0;  
                                 }  
                                 *nfrontp++ = pointer[i];  
                             } else {  
                                 sprintf(nfrontp, "\" %03o " + noquote,  
                                                         pointer[i]);  
                                 nfrontp += strlen(nfrontp);  
                                 noquote = 2;  
                             }  
1208                              break;                              break;
1209                          }                          }
1210                          pointer[k++] = pointer[j++];
1211                      }                      }
1212                      if (!noquote)                    printsub(0, &pointer[i], k - i);
1213                          *nfrontp++ = '"';                    if (i < length)
1214                      break;                      {
1215                          debug_output_data (" SE");
1216                          i = j;
1217                        } else
1218                          i = j - 1;
1219    
1220                      debug_output_data ("\r\n");
1221                      break;
1222    
1223                    default:
1224                      debug_output_data (" %d", pointer[i]);
1225                      break;
1226                  }                  }
1227              }              }
1228              break;            break;
1229            }
1230            break;
1231          }
1232    
1233  #if     defined(AUTHENTICATION)      case TELOPT_XDISPLOC:
1234          case TELOPT_AUTHENTICATION:        debug_output_data ("X-DISPLAY-LOCATION ");
1235              sprintf(nfrontp, "AUTHENTICATION");        switch (pointer[1])
1236              nfrontp += strlen(nfrontp);          {
1237            case TELQUAL_IS:
1238              if (length < 2) {            debug_output_data ("IS \"%.*s\"", length-2, (char *)pointer+2);
1239                  sprintf(nfrontp, " (empty suboption??\?)");            break;
1240                  nfrontp += strlen(nfrontp);          case TELQUAL_SEND:
1241                  break;            debug_output_data ("SEND");
1242              }            break;
1243              switch (pointer[1]) {          default:
1244              case TELQUAL_REPLY:            debug_output_data ("- unknown qualifier %d (0x%x).",
1245              case TELQUAL_IS:                         pointer[1], pointer[1]);
1246                  sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?          }
1247                                                          "IS" : "REPLY");        break;
1248                  nfrontp += strlen(nfrontp);  
1249                  if (AUTHTYPE_NAME_OK(pointer[2]))      case TELOPT_NEW_ENVIRON:
1250                      sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));        debug_output_data ("NEW-ENVIRON ");
1251                  else        goto env_common1;
1252                      sprintf(nfrontp, "%d ", pointer[2]);        
1253                  nfrontp += strlen(nfrontp);      case TELOPT_OLD_ENVIRON:
1254                  if (length < 3) {        debug_output_data ("OLD-ENVIRON");
1255                      sprintf(nfrontp, "(partial suboption??\?)");      env_common1:
1256                      nfrontp += strlen(nfrontp);        switch (pointer[1])
1257            {
1258            case TELQUAL_IS:
1259              debug_output_data ("IS ");
1260              goto env_common;
1261    
1262            case TELQUAL_SEND:
1263              debug_output_data ("SEND ");
1264              goto env_common;
1265    
1266            case TELQUAL_INFO:
1267              debug_output_data ("INFO ");
1268    
1269            env_common:
1270              {
1271                register int noquote = 2;
1272                for (i = 2; i < length; i++ )
1273                  {
1274                    switch (pointer[i])
1275                      {
1276                      case NEW_ENV_VAR:
1277                        debug_output_data ("\" VAR " + noquote);
1278                        noquote = 2;
1279                        break;
1280                        
1281                      case NEW_ENV_VALUE:
1282                        debug_output_data ("\" VALUE " + noquote);
1283                        noquote = 2;
1284                      break;                      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;  
1285    
1286              case TELQUAL_SEND:                    case ENV_ESC:
1287                  i = 2;                      debug_output_data ("\" ESC " + noquote);
1288                  sprintf(nfrontp, " SEND ");                      noquote = 2;
1289                  nfrontp += strlen(nfrontp);                      break;
1290                  while (i < length) {                      
1291                      if (AUTHTYPE_NAME_OK(pointer[i]))                    case ENV_USERVAR:
1292                          sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));                      debug_output_data ("\" USERVAR " + noquote);
1293                        noquote = 2;
1294                        break;
1295                        
1296                      default:
1297                      def_case:
1298                        if (isprint(pointer[i]) && pointer[i] != '"')
1299                          {
1300                            if (noquote)
1301                              {
1302                                debug_output_data ("\"");
1303                                noquote = 0;
1304                              }
1305                            debug_output_datalen (&pointer[i], 1);
1306                          }
1307                      else                      else
1308                          sprintf(nfrontp, "%d ", pointer[i]);                        {
1309                      nfrontp += strlen(nfrontp);                          debug_output_data ("\" %03o " + noquote,
1310                      if (++i >= length) {                                       pointer[i]);
1311                          sprintf(nfrontp, "(partial suboption??\?)");                          noquote = 2;
1312                          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);  
                     }  
1313                      break;                      break;
1314              }                    }
1315                  }
1316                if (!noquote)
1317                  debug_output_data ("\"");
1318              break;              break;
1319  #endif            }
1320            }
1321  #ifdef  ENCRYPTION        break;
         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;  
1322    
1323              case ENCRYPT_IS:  #if     defined(AUTHENTICATION)
1324              case ENCRYPT_REPLY:      case TELOPT_AUTHENTICATION:
1325                  sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?        debug_output_data ("AUTHENTICATION");
                                                         "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;  
1326    
1327              case ENCRYPT_SUPPORT:        if (length < 2)
1328                  i = 2;          {
1329                  sprintf(nfrontp, " SUPPORT ");            debug_output_data (" (empty suboption??\?)");
1330                  nfrontp += strlen(nfrontp);            break;
1331                  while (i < length) {          }
1332                      if (ENCTYPE_NAME_OK(pointer[i]))        switch (pointer[1])
1333                          sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));          {
1334                      else          case TELQUAL_REPLY:
1335                          sprintf(nfrontp, "%d ", pointer[i]);          case TELQUAL_IS:
1336                      nfrontp += strlen(nfrontp);            debug_output_data (" %s ", (pointer[1] == TELQUAL_IS) ?
1337                      i++;                         "IS" : "REPLY");
1338              if (AUTHTYPE_NAME_OK(pointer[2]))
1339                debug_output_data ("%s ", AUTHTYPE_NAME(pointer[2]));
1340              else
1341                debug_output_data ("%d ", pointer[2]);
1342              if (length < 3)
1343                {
1344                  debug_output_data ("(partial suboption??\?)");
1345                  break;
1346                }
1347              debug_output_data ("%s|%s",
1348                           ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
1349                           "CLIENT" : "SERVER",
1350                           ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
1351                           "MUTUAL" : "ONE-WAY");
1352    
1353              auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1354              debug_output_data ("%s", buf);
1355              break;
1356    
1357            case TELQUAL_SEND:
1358              i = 2;
1359              debug_output_data (" SEND ");
1360              while (i < length)
1361                {
1362                  if (AUTHTYPE_NAME_OK(pointer[i]))
1363                    debug_output_data ("%s ", AUTHTYPE_NAME(pointer[i]));
1364                  else
1365                    debug_output_data ("%d ", pointer[i]);
1366                  if (++i >= length)
1367                    {
1368                      debug_output_data ("(partial suboption??\?)");
1369                      break;
1370                  }                  }
1371                  break;                debug_output_data ("%s|%s ",
1372                               ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
1373                               "CLIENT" : "SERVER",
1374                               ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
1375                               "MUTUAL" : "ONE-WAY");
1376                  ++i;
1377                }
1378              break;
1379              
1380            case TELQUAL_NAME:
1381              i = 2;
1382              debug_output_data (" NAME \"");
1383              debug_output_datalen (&pointer[i], length);
1384              i += length;
1385              debug_output_data ("\"");
1386              break;
1387    
1388              case ENCRYPT_ENC_KEYID:          default:
1389                  sprintf(nfrontp, " ENC_KEYID", pointer[1]);            for (i = 2; i < length; i++)
1390                  nfrontp += strlen(nfrontp);              debug_output_data (" ?%d?", pointer[i]);
1391                  goto encommon;            break;
1392            }
1393              case ENCRYPT_DEC_KEYID:        break;
1394                  sprintf(nfrontp, " DEC_KEYID", pointer[1]);  #endif
                 nfrontp += strlen(nfrontp);  
                 goto encommon;  
1395    
1396              default:  #ifdef  ENCRYPTION
1397                  sprintf(nfrontp, " %d (unknown)", pointer[1]);      case TELOPT_ENCRYPT:
1398                  nfrontp += strlen(nfrontp);        debug_output_data ("ENCRYPT");
1399              encommon:        if (length < 2)
1400                  for (i = 2; i < length; i++) {          {
1401                      sprintf(nfrontp, " %d", pointer[i]);            debug_output_data (" (empty suboption??\?)");
1402                      nfrontp += strlen(nfrontp);            break;
1403                  }          }
1404                  break;        switch (pointer[1])
1405              }          {
1406              break;          case ENCRYPT_START:
1407  #endif  /* ENCRYPTION */            debug_output_data (" START");
1408              break;
1409    
1410            case ENCRYPT_END:
1411              debug_output_data (" END");
1412              break;
1413              
1414            case ENCRYPT_REQSTART:
1415              debug_output_data (" REQUEST-START");
1416              break;
1417              
1418            case ENCRYPT_REQEND:
1419              debug_output_data (" REQUEST-END");
1420              break;
1421    
1422            case ENCRYPT_IS:
1423            case ENCRYPT_REPLY:
1424              debug_output_data (" %s ", (pointer[1] == ENCRYPT_IS) ?
1425                           "IS" : "REPLY");
1426              if (length < 3)
1427                {
1428                  debug_output_data (" (partial suboption??\?)");
1429                  break;
1430                }
1431              if (ENCTYPE_NAME_OK(pointer[2]))
1432                debug_output_data ("%s ", ENCTYPE_NAME(pointer[2]));
1433              else
1434                debug_output_data (" %d (unknown)", pointer[2]);
1435              
1436              encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1437              debug_output_data ("%s", buf);
1438              break;
1439    
1440            case ENCRYPT_SUPPORT:
1441              i = 2;
1442              debug_output_data (" SUPPORT ");
1443              while (i < length)
1444                {
1445                  if (ENCTYPE_NAME_OK(pointer[i]))
1446                    debug_output_data ("%s ", ENCTYPE_NAME(pointer[i]));
1447                  else
1448                    debug_output_data ("%d ", pointer[i]);
1449                  i++;
1450                }
1451              break;
1452              
1453            case ENCRYPT_ENC_KEYID:
1454              debug_output_data (" ENC_KEYID", pointer[1]);
1455              goto encommon;
1456              
1457            case ENCRYPT_DEC_KEYID:
1458              debug_output_data (" DEC_KEYID", pointer[1]);
1459              goto encommon;
1460    
1461          default:          default:
1462              if (TELOPT_OK(pointer[0]))            debug_output_data (" %d (unknown)", pointer[1]);
1463                  sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));          encommon:
1464              else            for (i = 2; i < length; i++)
1465                  sprintf(nfrontp, "%d (unknown)", pointer[i]);              debug_output_data (" %d", pointer[i]);
1466              nfrontp += strlen(nfrontp);            break;
             for (i = 1; i < length; i++) {  
                 sprintf(nfrontp, " %d", pointer[i]);  
                 nfrontp += strlen(nfrontp);  
             }  
             break;  
1467          }          }
1468          sprintf(nfrontp, "\r\n");        break;
1469          nfrontp += strlen(nfrontp);  #endif  /* ENCRYPTION */
1470    
1471        default:
1472          if (TELOPT_OK(pointer[0]))
1473            debug_output_data ("%s (unknown)", TELOPT(pointer[0]));
1474          else
1475            debug_output_data ("%d (unknown)", pointer[i]);
1476          for (i = 1; i < length; i++)
1477            debug_output_data (" %d", pointer[i]);
1478          break;
1479        }
1480      debug_output_data ("\r\n");
1481  }  }
1482    
1483  /*  /*
1484   * 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.
1485   */   */
1486  void  void
1487  printdata(register char *tag, register char *ptr, register int cnt  printdata(register char *tag, register char *ptr, register int cnt)
1488  {  {
1489          register int i;    register int i;
1490          char xbuf[30];    char xbuf[30];
1491      
1492          while (cnt) {    while (cnt)
1493                  /* flush net output buffer if no room for new data) */      {
1494                  if ((&netobuf[BUFSIZ] - nfrontp) < 80) {        /* add a line of output */
1495                          netflush();        debug_output_data ("%s: ", tag);
1496                  }        for (i = 0; i < 20 && cnt; i++)
1497            {
1498              debug_output_data ("%02x", *ptr);
1499              xbuf[i] = isprint(*ptr) ? *ptr : '.';
1500    
1501                  /* add a line of output */            if (i % 2)
1502                  sprintf(nfrontp, "%s: ", tag);              debug_output_data (" ");
1503                  nfrontp += strlen(nfrontp);            cnt--;
1504                  for (i = 0; i < 20 && cnt; i++) {            ptr++;
                         sprintf(nfrontp, "%02x", *ptr);  
                         nfrontp += strlen(nfrontp);  
                         if (isprint(*ptr)) {  
                                 xbuf[i] = *ptr;  
                         } else {  
                                 xbuf[i] = '.';  
                         }  
                         if (i % 2) {  
                                 *nfrontp = ' ';  
                                 nfrontp++;  
                         }  
                         cnt--;  
                         ptr++;  
                 }  
                 xbuf[i] = '\0';  
                 sprintf(nfrontp, " %s\r\n", xbuf );  
                 nfrontp += strlen(nfrontp);  
1505          }          }
1506    
1507          xbuf[i] = '\0';
1508          debug_output_data (" %s\r\n", xbuf );
1509        }
1510  }  }
1511  #endif /* DIAGNOSTICS */  
1512    #if defined(AUTHENTICATION) || defined(ENCRYPTION)
1513    
1514    int
1515    net_write (unsigned char *str, int len)
1516    {
1517      return net_output_datalen (str, len);
1518    }
1519    
1520    void
1521    net_encrypt ()
1522    {
1523    #ifdef  ENCRYPTION
1524      char *s = (nclearto > nbackp) ? nclearto : nbackp;
1525      if (s < nfrontp && encrypt_output)
1526        (*encrypt_output)((unsigned char *)s, nfrontp - s);
1527      nclearto = nfrontp;
1528    #endif /* ENCRYPTION */
1529    }
1530    
1531    int
1532    telnet_spin()
1533    {
1534      io_drain ();
1535      return 0;
1536    }
1537    
1538    
1539    #endif

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26