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