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