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