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