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