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 /* based on @(#)utility.c	8.1 (Berkeley) 6/4/93 */
35 
36 #include <autoconf.h>
37 
38 #include <stdarg.h>
39 #define PRINTOPTIONS
40 #include "telnetd.h"
41 
42 #ifdef HAVE_SYS_UTSNAME_H
43 #include <sys/utsname.h>
44 #endif
45 
46 #if	defined(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     void netflush();
70 
71     DIAG(TD_REPORT, netputs("td: ttloop\r\n"));
72     if (nfrontp-nbackp) {
73 	netflush();
74     }
75 read_again:
76     ncc = read(net, netibuf, sizeof netibuf);
77     if (ncc < 0) {
78 	if (errno == EINTR)
79 	    goto read_again;
80 	syslog(LOG_INFO, "ttloop:  read: %m");
81 	exit(1);
82     } else if (ncc == 0) {
83 	syslog(LOG_INFO, "ttloop:  peer died: %m");
84 	exit(1);
85     }
86     DIAG(TD_REPORT, netprintf("td: ttloop read %d chars\r\n", ncc));
87     netip = netibuf;
88     telrcv();			/* state machine */
89     if (ncc > 0) {
90 	pfrontp = pbackp = ptyobuf;
91 	telrcv();
92     }
93 }  /* end of ttloop */
94 
95 /*
96  * ttsuck - This is a horrible kludge to deal with a bug in
97  * HostExplorer. HostExplorer thinks it knows how to do krb5 auth, but
98  * it doesn't really. So if you offer it krb5 as an auth choice before
99  * krb4, it will sabotage the connection. So we peek ahead into the
100  * input stream to see if the client is a UNIX client, and then
101  * (later) offer krb5 first only if it is. Since no Mac/PC telnet
102  * clients do auto switching between krb4 and krb5 like the UNIX
103  * client does, it doesn't matter what order they see the choices in
104  * (except for HostExplorer).
105  *
106  * It is actually not possible to do this without looking ahead into
107  * the input stream: the client and server both try to begin
108  * auth/encryption negotiation as soon as possible, so if we let the
109  * server process things normally, it will already have sent the list
110  * of supported auth types before seeing the NEW-ENVIRON option. If
111  * you change the code to hold off sending the list of supported auth
112  * types until after it knows whether or not the remote side supports
113  * NEW-ENVIRON, then the auth negotiation and encryption negotiation
114  * race conditions won't interact properly, and encryption negotiation
115  * will reliably fail.
116  */
117 
118     void
ttsuck()119 ttsuck()
120 {
121     extern int auth_client_non_unix;
122     int nread;
123     struct timeval tv;
124     fd_set fds;
125     char *p, match[] = {IAC, WILL, TELOPT_NEW_ENVIRON};
126 
127     if (nfrontp-nbackp) {
128 	netflush();
129     }
130     tv.tv_sec = 1;
131     tv.tv_usec = 0;
132     FD_SET(net, &fds);
133 
134     while (select(net + 1, &fds, NULL, NULL, &tv) == 1)
135       {
136 	nread = read(net, netibuf + ncc, sizeof(netibuf) - ncc);
137 	if (nread <= 0)
138 	  break;
139 	ncc += nread;
140       }
141 
142     auth_client_non_unix = 1;
143     for (p = netibuf; p < netibuf + ncc; p++)
144       {
145 	if (!memcmp(p, match, sizeof(match)))
146 	  {
147 	    auth_client_non_unix = 0;
148 	    break;
149 	  }
150       }
151 
152     if (ncc > 0)
153       telrcv();
154 }
155 
156 /*
157  * Check a descriptor to see if out of band data exists on it.
158  */
159     int
stilloob(s)160 stilloob(s)
161     int	s;		/* socket number */
162 {
163     static struct timeval timeout = { 0 };
164     fd_set	excepts;
165     int value;
166 
167     do {
168 	FD_ZERO(&excepts);
169 	FD_SET(s, &excepts);
170 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
171     } while ((value == -1) && (errno == EINTR));
172 
173     if (value < 0) {
174 	fatalperror(pty, "select");
175     }
176     if (FD_ISSET(s, &excepts)) {
177 	return 1;
178     } else {
179 	return 0;
180     }
181 }
182 
183 	void
ptyflush()184 ptyflush()
185 {
186 	int n;
187 
188 	if ((n = pfrontp - pbackp) > 0) {
189 		DIAG((TD_REPORT | TD_PTYDATA),
190 		     netprintf("td: ptyflush %d chars\r\n", n));
191 		DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
192 		n = write(pty, pbackp, (unsigned) n);
193 	}
194 	if (n < 0) {
195 		if (errno == EWOULDBLOCK || errno == EINTR)
196 			return;
197 		(void)signal(SIGCHLD, SIG_DFL);
198 		cleanup(0);
199 	}
200 	pbackp += n;
201 	if (pbackp == pfrontp)
202 		pbackp = pfrontp = ptyobuf;
203 }
204 
205 /*
206  * nextitem()
207  *
208  *	Return the address of the next "item" in the TELNET data
209  * stream.  This will be the address of the next character if
210  * the current address is a user data character, or it will
211  * be the address of the character following the TELNET command
212  * if the current address is a TELNET IAC ("I Am a Command")
213  * character.
214  */
215 static char *
nextitem(current)216 nextitem(current)
217     char	*current;
218 {
219     if ((*current&0xff) != IAC) {
220 	return current+1;
221     }
222     switch (*(current+1)&0xff) {
223     case DO:
224     case DONT:
225     case WILL:
226     case WONT:
227 	return current+3;
228     case SB:		/* loop forever looking for the SE */
229 	{
230 	    register char *look = current+2;
231 
232 	    for (;;) {
233 		if ((*look++&0xff) == IAC) {
234 		    if ((*look++&0xff) == SE) {
235 			return look;
236 		    }
237 		}
238 	    }
239 	}
240     default:
241 	return current+2;
242     }
243 }  /* end of nextitem */
244 
245 
246 /*
247  * netclear()
248  *
249  *	We are about to do a TELNET SYNCH operation.  Clear
250  * the path to the network.
251  *
252  *	Things are a bit tricky since we may have sent the first
253  * byte or so of a previous TELNET command into the network.
254  * So, we have to scan the network buffer from the beginning
255  * until we are up to where we want to be.
256  *
257  *	A side effect of what we do, just to keep things
258  * simple, is to clear the urgent data pointer.  The principal
259  * caller should be setting the urgent data pointer AFTER calling
260  * us in any case.
261  */
262     void
netclear()263 netclear()
264 {
265     register char *thisitem, *next;
266     char *good;
267 #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
268 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
269 
270 #ifdef	ENCRYPTION
271     thisitem = nclearto > netobuf ? nclearto : netobuf;
272 #else	/* ENCRYPTION */
273     thisitem = netobuf;
274 #endif	/* ENCRYPTION */
275 
276     while ((next = nextitem(thisitem)) <= nbackp) {
277 	thisitem = next;
278     }
279 
280     /* Now, thisitem is first before/at boundary. */
281 
282 #ifdef	ENCRYPTION
283     good = nclearto > netobuf ? nclearto : netobuf;
284 #else	/* ENCRYPTION */
285     good = netobuf;	/* where the good bytes go */
286 #endif	/* ENCRYPTION */
287 
288     while (nfrontp > thisitem) {
289 	if (wewant(thisitem)) {
290 	    unsigned int length;
291 
292 	    next = thisitem;
293 	    do {
294 		next = nextitem(next);
295 	    } while (wewant(next) && (nfrontp > next));
296 	    length = next-thisitem;
297 	    memcpy(good, thisitem, length);
298 	    good += length;
299 	    thisitem = next;
300 	} else {
301 	    thisitem = nextitem(thisitem);
302 	}
303     }
304 
305     nbackp = netobuf;
306     nfrontp = good;		/* next byte to be sent */
307     neturg = 0;
308 }  /* end of netclear */
309 
310 /*
311  *  netflush
312  *		Send as much data as possible to the network,
313  *	handling requests for urgent data.
314  */
315 void
netflush()316 netflush()
317 {
318     int n;
319     extern int not42;
320 
321     if ((n = nfrontp - nbackp) > 0) {
322 	DIAG(TD_REPORT, {netprintf_noflush("td: netflush %d chars\r\n", n);
323 			 n = nfrontp - nbackp;});
324 #ifdef	ENCRYPTION
325 	if (encrypt_output) {
326 		char *s = nclearto ? nclearto : nbackp;
327 		if (nfrontp - s > 0) {
328 			(*encrypt_output)((unsigned char *)s, nfrontp-s);
329 			nclearto = nfrontp;
330 		}
331 	}
332 #endif	/* ENCRYPTION */
333 	/*
334 	 * if no urgent data, or if the other side appears to be an
335 	 * old 4.2 client (and thus unable to survive TCP urgent data),
336 	 * write the entire buffer in non-OOB mode.
337 	 */
338 	if ((neturg == 0) || (not42 == 0)) {
339 	    n = write(net, nbackp, (unsigned) n);	/* normal write */
340 	} else {
341 	    n = neturg - nbackp;
342 	    /*
343 	     * In 4.2 (and 4.3) systems, there is some question about
344 	     * what byte in a sendOOB operation is the "OOB" data.
345 	     * To make ourselves compatible, we only send ONE byte
346 	     * out of band, the one WE THINK should be OOB (though
347 	     * we really have more the TCP philosophy of urgent data
348 	     * rather than the Unix philosophy of OOB data).
349 	     */
350 	    if (n > 1) {
351 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
352 	    } else {
353 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
354 	    }
355 	}
356     }
357     if (n < 0) {
358 	if (errno == EWOULDBLOCK || errno == EINTR)
359 		return;
360 	(void)signal(SIGCHLD, SIG_DFL);
361 	cleanup(0);
362     }
363     nbackp += n;
364 #ifdef	ENCRYPTION
365     if (nbackp > nclearto)
366 	nclearto = 0;
367 #endif	/* ENCRYPTION */
368     if (nbackp >= neturg) {
369 	neturg = 0;
370     }
371     if (nbackp == nfrontp) {
372 	nbackp = nfrontp = netobuf;
373 #ifdef	ENCRYPTION
374 	nclearto = 0;
375 #endif	/* ENCRYPTION */
376     }
377     return;
378 }  /* end of netflush */
379 
380 /*
381  * L8_256(x) = log8(256**x), rounded up, including sign (for decimal
382  * strings too).  log8(256) = 8/3, but we use integer math to round
383  * up.
384  */
385 #define L8_256(x) (((x * 8 + 2) / 3) + 1)
386 
387 /*
388  * netprintf
389  *
390  * Do the equivalent of printf() to the NETOBUF "ring buffer",
391  * possibly calling netflush() if needed.
392  *
393  * Thou shalt not call this with a "%s" format; use netputs instead.
394  * We also don't deal with floating point widths in here.
395  */
396 static void
397 netprintf_ext(int noflush, int seturg, const char *fmt, va_list args)
398 #if !defined(__cplusplus) && (__GNUC__ > 2)
399     __attribute__((__format__(__printf__, 3, 0)))
400 #endif
401     ;
402 
403 static void
netprintf_ext(int noflush,int seturg,const char * fmt,va_list args)404 netprintf_ext(int noflush, int seturg, const char *fmt, va_list args)
405 {
406 	size_t remain;
407 	size_t maxoutlen;
408 	char buf[BUFSIZ];
409 	const char *cp;
410 	int len;
411 
412 	buf[0] = '\0';		/* nul-terminate */
413 	remain = sizeof(netobuf) - (nfrontp - netobuf);
414 	for (maxoutlen = 0, cp = fmt; *cp; cp++) {
415 		if (*cp == '%')
416 			/* Ok so this is slightly overkill... */
417 			maxoutlen += L8_256(sizeof(long));
418 		else
419 			maxoutlen++;
420 	}
421 	if (maxoutlen >= sizeof(buf))
422 		return;		/* highly unlikely */
423 
424 	len = vsnprintf(buf, sizeof(buf), fmt, args);
425 
426 	/*
427 	 * The return value from sprintf()-like functions may be the
428 	 * number of characters that *would* have been output, not the
429 	 * number actually output.
430 	 */
431 	if (len <= 0 || (size_t) len > sizeof(buf))
432 		return;
433 	if (remain < (size_t) len && !noflush) {
434 		netflush();
435 		remain = sizeof(netobuf) - (nfrontp - netobuf);
436 	}
437 	if (remain < (size_t) len)
438 		return;		/* still not enough space? */
439 	memcpy(nfrontp, buf, (size_t)len);
440 	nfrontp += len;
441 	if (seturg)
442 		neturg = nfrontp - 1;
443 }
444 
445 void
netprintf(const char * fmt,...)446 netprintf(const char *fmt, ...)
447 {
448 	va_list args;
449 
450 	va_start(args, fmt);
451 	netprintf_ext(0, 0, fmt, args);
452 	va_end(args);
453 }
454 
455 void
netprintf_urg(const char * fmt,...)456 netprintf_urg(const char *fmt, ...)
457 {
458 	va_list args;
459 
460 	va_start(args, fmt);
461 	netprintf_ext(0, 1, fmt, args);
462 	va_end(args);
463 }
464 
465 void
netprintf_noflush(const char * fmt,...)466 netprintf_noflush(const char *fmt, ...)
467 {
468 	va_list args;
469 
470 	va_start(args, fmt);
471 	netprintf_ext(1, 0, fmt, args);
472 	va_end(args);
473 }
474 
475 /*
476  * netwrite
477  *
478  * Copy BUF into the NETOBUF "ring buffer", possibly calling
479  * netflush() if needed.
480  */
481 int
netwrite(const unsigned char * buf,size_t len)482 netwrite(const unsigned char *buf, size_t len)
483 {
484 	int remaining, copied;
485 
486 	remaining = BUFSIZ - (nfrontp - netobuf);
487 	while (len > 0) {
488 		/* Free up enough space if the room is too low*/
489 		if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
490 			netflush();
491 			remaining = BUFSIZ - (nfrontp - netobuf);
492 		}
493 
494 		/* Copy out as much as will fit */
495 		copied = remaining > len ? len : remaining;
496 		memmove(nfrontp, buf, copied);
497 		nfrontp += copied;
498 		len -= copied;
499 		remaining -= copied;
500 		buf += copied;
501 	}
502 	return copied;
503 }
504 
505 /*
506  * netputs
507  *
508  * Write S to the NETOBUF "ring buffer".  Does not write a '\n'.
509  */
510 void
netputs(const char * s)511 netputs(const char *s)
512 {
513 	netwrite((const unsigned char *) s, strlen(s));
514 }
515 
516 /*
517  * miscellaneous functions doing a variety of little jobs follow ...
518  */
519 
520 
521 	void
fatal(f,msg)522 fatal(f, msg)
523 	int f;
524 	const char *msg;
525 {
526 	char buf[BUFSIZ];
527 
528 	(void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
529 #ifdef	ENCRYPTION
530 	if (encrypt_output) {
531 		/*
532 		 * Better turn off encryption first....
533 		 * Hope it flushes...
534 		 */
535 		encrypt_send_end();
536 		netflush();
537 	}
538 #endif	/* ENCRYPTION */
539 	(void) write(f, buf, strlen(buf));
540 	sleep(1);	/*XXX*/
541 	exit(1);
542 }
543 
544 	void
fatalperror(f,msg)545 fatalperror(f, msg)
546 	int f;
547 	const char *msg;
548 {
549 	char buf[BUFSIZ], *strerror();
550 
551 	(void) snprintf(buf, sizeof(buf), "%s: %s\r\n", msg, strerror(errno));
552 	fatal(f, buf);
553 }
554 
555 char editedhost[32];
556 
557 	void
edithost(pat,host)558 edithost(pat, host)
559 	register char *pat;
560 	register char *host;
561 {
562 	register char *res = editedhost;
563 
564 	if (!pat)
565 		pat = "";
566 	while (*pat) {
567 		switch (*pat) {
568 
569 		case '#':
570 			if (*host)
571 				host++;
572 			break;
573 
574 		case '@':
575 			if (*host)
576 				*res++ = *host++;
577 			break;
578 
579 		default:
580 			*res++ = *pat;
581 			break;
582 		}
583 		if (res == &editedhost[sizeof editedhost - 1]) {
584 			*res = '\0';
585 			return;
586 		}
587 		pat++;
588 	}
589 	if (*host)
590 		(void) strncpy(res, host,
591 				sizeof editedhost - (res - editedhost) -1);
592 	else
593 		*res = '\0';
594 	editedhost[sizeof editedhost - 1] = '\0';
595 }
596 
597 static char *putlocation;
598 
599 static	void
putstr(s)600 putstr(s)
601 	register char *s;
602 {
603 
604 	while (*s)
605 		putchr(*s++);
606 }
607 
608 	void
putchr(cc)609 putchr(cc)
610 	int cc;
611 {
612 	*putlocation++ = cc;
613 }
614 
615 /*
616  * This is split on two lines so that SCCS will not see the M
617  * between two % signs and expand it...
618  */
619 static char fmtstr[] = { "%l:%M\
620 %P on %A, %d %B %Y" };
621 
622 	void
putf(cp,where)623 putf(cp, where)
624 	register char *cp;
625 	char *where;
626 {
627 	char *slash;
628 	time_t t;
629 	char db[100];
630 #ifdef HAVE_SYS_UTSNAME_H
631 	struct utsname utsinfo;
632 
633 	(void) uname(&utsinfo);
634 #endif
635 
636 	putlocation = where;
637 
638 	while (*cp) {
639 		if (*cp != '%') {
640 			putchr(*cp++);
641 			continue;
642 		}
643 		switch (*++cp) {
644 
645 		case 't':
646 #ifdef	STREAMSPTY
647 			/* names are like /dev/pts/2 -- we want pts/2 */
648 			slash = strchr(line+1, '/');
649 #else
650 			slash = strrchr(line, '/');
651 #endif
652 			if (slash == (char *) 0)
653 				putstr(line);
654 			else
655 				putstr(&slash[1]);
656 			break;
657 
658 		case 'h':
659 			putstr(editedhost);
660 			break;
661 
662 		case 'd':
663 			(void)time(&t);
664 			(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
665 			putstr(db);
666 			break;
667 
668 #ifdef HAVE_SYS_UTSNAME_H
669 		case 's':
670 			putstr(utsinfo.sysname);
671 			break;
672 
673 		case 'm':
674 			putstr(utsinfo.machine);
675 			break;
676 
677 		case 'r':
678 			putstr(utsinfo.release);
679 			break;
680 
681 		case 'v':
682 			putstr(utsinfo.version);
683 			break;
684 #endif
685 
686 		case '%':
687 			putchr('%');
688 			break;
689 		}
690 		cp++;
691 	}
692 }
693 
694 #ifdef DIAGNOSTICS
695 /*
696  * Print telnet options and commands in plain text, if possible.
697  */
698 void
printoption(fmt,option)699 printoption(fmt, option)
700 	register char *fmt;
701 	register int option;
702 {
703 	netputs(fmt);
704 	netputs(" ");
705 	if (TELOPT_OK(option)) {
706 		netputs(TELOPT(option));
707 		netputs("\r\n");
708 	} else if (TELCMD_OK(option)) {
709 		netputs(TELCMD(option));
710 		netputs("\r\n");
711 	} else {
712 		netprintf("%d\r\n", option);
713 	}
714 	return;
715 }
716 
717 void
printsub(direction,pointer,length)718 printsub(direction, pointer, length)
719     char		direction;	/* '<' or '>' */
720     unsigned char	*pointer;	/* where suboption data sits */
721     int			length;		/* length of suboption data */
722 {
723     register int i = 0;
724     char buf[512];
725 
726         if (!(diagnostic & TD_OPTIONS))
727 		return;
728 
729 	if (direction) {
730 	    netputs("td: ");
731 	    netputs(direction == '<' ? "recv" : "send");
732 	    netputs(" suboption ");
733 	    if (length >= 3) {
734 		register int j;
735 
736 		i = pointer[length-2];
737 		j = pointer[length-1];
738 
739 		if (i != IAC || j != SE) {
740 		    netputs("(terminated by ");
741 		    if (TELOPT_OK(i))
742 			netputs(TELOPT(i));
743 		    else if (TELCMD_OK(i))
744 			netputs(TELCMD(i));
745 		    else
746 			netprintf("%d", i);
747 		    netputs(" ");
748 		    if (TELOPT_OK(j))
749 			netputs(TELOPT(j));
750 		    else if (TELCMD_OK(j))
751 			netputs(TELCMD(j));
752 		    else
753 			netprintf("%d", j);
754 		    netputs(", not IAC SE!) ");
755 		}
756 	    }
757 	    length -= 2;
758 	}
759 	if (length < 1) {
760 	    netputs("(Empty suboption??\?)");
761 	    return;
762 	}
763 	switch (pointer[0]) {
764 	case TELOPT_TTYPE:
765 	    netputs("TERMINAL-TYPE ");
766 	    switch (pointer[1]) {
767 	    case TELQUAL_IS:
768 		netputs("IS \"");
769 		netwrite(pointer + 2, (size_t)(length - 2));
770 		netputs("\"");
771 		break;
772 	    case TELQUAL_SEND:
773 		netputs("SEND");
774 		break;
775 	    default:
776 		netprintf("- unknown qualifier %d (0x%x).",
777 			  pointer[1], pointer[1]);
778 	    }
779 	    break;
780 	case TELOPT_TSPEED:
781 	    netputs("TERMINAL-SPEED ");
782 	    if (length < 2) {
783 		netputs("(empty suboption??\?)");
784 		break;
785 	    }
786 	    switch (pointer[1]) {
787 	    case TELQUAL_IS:
788 		netputs("IS ");
789 		netwrite(pointer + 2, (size_t)(length - 2));
790 		break;
791 	    default:
792 		if (pointer[1] == 1)
793 		    netputs("SEND");
794 		else
795 		    netprintf("%d (unknown)", pointer[1]);
796 		for (i = 2; i < length; i++)
797 		    netprintf(" ?%d?", pointer[i]);
798 		break;
799 	    }
800 	    break;
801 
802 	case TELOPT_LFLOW:
803 	    netputs("TOGGLE-FLOW-CONTROL ");
804 	    if (length < 2) {
805 		netputs("(empty suboption??\?)");
806 		break;
807 	    }
808 	    switch (pointer[1]) {
809 	    case LFLOW_OFF:
810 		netputs("OFF"); break;
811 	    case LFLOW_ON:
812 		netputs("ON"); break;
813 	    case LFLOW_RESTART_ANY:
814 		netputs("RESTART-ANY"); break;
815 	    case LFLOW_RESTART_XON:
816 		netputs("RESTART-XON"); break;
817 	    default:
818 		netprintf("%d (unknown)", pointer[1]);
819 	    }
820 	    for (i = 2; i < length; i++)
821 		netprintf(" ?%d?", pointer[i]);
822 	    break;
823 
824 	case TELOPT_NAWS:
825 	    netputs("NAWS");
826 	    if (length < 2) {
827 		netputs(" (empty suboption??\?)");
828 		break;
829 	    }
830 	    if (length == 2) {
831 		netprintf(" ?%d?", pointer[1]);
832 		break;
833 	    }
834 	    netprintf(" %d %d (%d)",
835 		pointer[1], pointer[2],
836 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
837 	    if (length == 4) {
838 		netprintf(" ?%d?", pointer[3]);
839 		break;
840 	    }
841 	    netprintf(" %d %d (%d)",
842 		pointer[3], pointer[4],
843 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
844 	    for (i = 5; i < length; i++)
845 		netprintf(" ?%d?", pointer[i]);
846 	    break;
847 
848 	case TELOPT_LINEMODE:
849 	    netputs("LINEMODE ");
850 	    if (length < 2) {
851 		netputs("(empty suboption??\?)");
852 		break;
853 	    }
854 	    switch (pointer[1]) {
855 	    case WILL:
856 		netputs("WILL ");
857 		goto common;
858 	    case WONT:
859 		netputs("WONT ");
860 		goto common;
861 	    case DO:
862 		netputs("DO ");
863 		goto common;
864 	    case DONT:
865 		netputs("DONT ");
866 	    common:
867 		if (length < 3) {
868 		    netputs("(no option??\?)");
869 		    break;
870 		}
871 		switch (pointer[2]) {
872 		case LM_FORWARDMASK:
873 		    netputs("Forward Mask");
874 		    for (i = 3; i < length; i++)
875 			netprintf(" %x", pointer[i]);
876 		    break;
877 		default:
878 		    netprintf("%d (unknown)", pointer[2]);
879 		    for (i = 3; i < length; i++)
880 			netprintf(" %d", pointer[i]);
881 		    break;
882 		}
883 		break;
884 
885 	    case LM_SLC:
886 		netputs("SLC");
887 		for (i = 2; i < length - 2; i += 3) {
888 		    if (SLC_NAME_OK(pointer[i+SLC_FUNC])) {
889 			netputs(" ");
890 			netputs(SLC_NAME(pointer[i+SLC_FUNC]));
891 		    } else
892 			netprintf(" %d", pointer[i+SLC_FUNC]);
893 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
894 		    case SLC_NOSUPPORT:
895 			netputs(" NOSUPPORT"); break;
896 		    case SLC_CANTCHANGE:
897 			netputs(" CANTCHANGE"); break;
898 		    case SLC_VARIABLE:
899 			netputs(" VARIABLE"); break;
900 		    case SLC_DEFAULT:
901 			netputs(" DEFAULT"); break;
902 		    }
903 		    netputs(pointer[i+SLC_FLAGS]&SLC_ACK
904 			    ? "|ACK" : "");
905 		    netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHIN
906 			    ? "|FLUSHIN" : "");
907 		    netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHOUT
908 			    ? "|FLUSHOUT" : "");
909 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
910 						SLC_FLUSHOUT| SLC_LEVELBITS)) {
911 			netprintf("(0x%x)", pointer[i+SLC_FLAGS]);
912 		    }
913 		    netprintf(" %d;", pointer[i+SLC_VALUE]);
914 		    if ((pointer[i+SLC_VALUE] == IAC) &&
915 			(pointer[i+SLC_VALUE+1] == IAC))
916 				i++;
917 		}
918 		for (; i < length; i++)
919 		    netprintf(" ?%d?", pointer[i]);
920 		break;
921 
922 	    case LM_MODE:
923 		netputs("MODE ");
924 		if (length < 3) {
925 		    netputs("(no mode??\?)");
926 		    break;
927 		}
928 		{
929 		    int wrotemode = 0;
930 
931 #define NETPUTS_MODE(x)				\
932 do {						\
933 	if (pointer[2] & (MODE_##x)) {		\
934 		if (wrotemode) netputs("|");	\
935 		netputs(#x);			\
936 		wrotemode++;			\
937 	}					\
938 } while (0)
939 		    NETPUTS_MODE(EDIT);
940 		    NETPUTS_MODE(TRAPSIG);
941 		    NETPUTS_MODE(SOFT_TAB);
942 		    NETPUTS_MODE(LIT_ECHO);
943 		    NETPUTS_MODE(ACK);
944 #undef NETPUTS_MODE
945 		    if (!wrotemode)
946 			netputs("0");
947 		}
948 		if (pointer[2] & ~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
949 		    netprintf(" (0x%x)", pointer[2]);
950 		for (i = 3; i < length; i++)
951 		    netprintf(" ?0x%x?", pointer[i]);
952 		break;
953 	    default:
954 		netprintf("%d (unknown)", pointer[1]);
955 		for (i = 2; i < length; i++)
956 		    netprintf(" %d", pointer[i]);
957 	    }
958 	    break;
959 
960 	case TELOPT_STATUS: {
961 	    register char *cp;
962 	    register int j, k;
963 
964 	    netputs("STATUS");
965 
966 	    switch (pointer[1]) {
967 	    default:
968 		if (pointer[1] == TELQUAL_SEND)
969 		    netputs(" SEND");
970 		else
971 		    netprintf(" %d (unknown)", pointer[1]);
972 		for (i = 2; i < length; i++)
973 		    netprintf(" ?%d?", pointer[i]);
974 		break;
975 	    case TELQUAL_IS:
976 		netputs(" IS\r\n");
977 
978 		for (i = 2; i < length; i++) {
979 		    switch(pointer[i]) {
980 		    case DO:	cp = "DO"; goto common2;
981 		    case DONT:	cp = "DONT"; goto common2;
982 		    case WILL:	cp = "WILL"; goto common2;
983 		    case WONT:	cp = "WONT"; goto common2;
984 		    common2:
985 			i++;
986 			netputs(" ");
987 			netputs(cp);
988 			netputs(" ");
989 			if (TELOPT_OK(pointer[i]))
990 			    netputs(TELOPT(pointer[i]));
991 			else
992 			    netprintf("%d", pointer[i]);
993 
994 			netputs("\r\n");
995 			break;
996 
997 		    case SB:
998 			netputs(" SB ");
999 			i++;
1000 			j = k = i;
1001 			while (j < length) {
1002 			    if (pointer[j] == SE) {
1003 				if (j+1 == length)
1004 				    break;
1005 				if (pointer[j+1] == SE)
1006 				    j++;
1007 				else
1008 				    break;
1009 			    }
1010 			    pointer[k++] = pointer[j++];
1011 			}
1012 			printsub(0, &pointer[i], k - i);
1013 			if (i < length) {
1014 			    netputs(" SE");
1015 			    i = j;
1016 			} else
1017 			    i = j - 1;
1018 
1019 			netputs("\r\n");
1020 
1021 			break;
1022 
1023 		    default:
1024 			netprintf(" %d", pointer[i]);
1025 			break;
1026 		    }
1027 		}
1028 		break;
1029 	    }
1030 	    break;
1031 	  }
1032 
1033 	case TELOPT_XDISPLOC:
1034 	    netputs("X-DISPLAY-LOCATION ");
1035 	    switch (pointer[1]) {
1036 	    case TELQUAL_IS:
1037 		netputs("IS \"");
1038 		netwrite(pointer + 2, (size_t)(length - 2));
1039 		netputs("\"");
1040 		break;
1041 	    case TELQUAL_SEND:
1042 		netputs("SEND");
1043 		break;
1044 	    default:
1045 		netprintf("- unknown qualifier %d (0x%x).",
1046 			  pointer[1], pointer[1]);
1047 	    }
1048 	    break;
1049 
1050 	case TELOPT_NEW_ENVIRON:
1051 	    netputs("NEW-ENVIRON ");
1052 	    goto env_common1;
1053 	case TELOPT_OLD_ENVIRON:
1054 	    netputs("OLD-ENVIRON ");
1055 	env_common1:
1056 	    switch (pointer[1]) {
1057 	    case TELQUAL_IS:
1058 		netputs("IS ");
1059 		goto env_common;
1060 	    case TELQUAL_SEND:
1061 		netputs("SEND ");
1062 		goto env_common;
1063 	    case TELQUAL_INFO:
1064 		netputs("INFO ");
1065 	    env_common:
1066 		{
1067 		    register int noquote = 2;
1068 		    for (i = 2; i < length; i++ ) {
1069 			switch (pointer[i]) {
1070 			case NEW_ENV_VAR:
1071 			    netputs("\" VAR " + noquote);
1072 			    noquote = 2;
1073 			    break;
1074 
1075 			case NEW_ENV_VALUE:
1076 			    netputs("\" VALUE " + noquote);
1077 			    noquote = 2;
1078 			    break;
1079 
1080 			case ENV_ESC:
1081 			    netputs("\" ESC " + noquote);
1082 			    noquote = 2;
1083 			    break;
1084 
1085 			case ENV_USERVAR:
1086 			    netputs("\" USERVAR " + noquote);
1087 			    noquote = 2;
1088 			    break;
1089 
1090 			default:
1091 			    if (isprint(pointer[i]) && pointer[i] != '"') {
1092 				if (noquote) {
1093 				    netputs("\"");
1094 				    noquote = 0;
1095 				}
1096 				netprintf("%c", pointer[i]);
1097 			    } else {
1098 				netprintf("\" %03o " + noquote,
1099 					  pointer[i]);
1100 				noquote = 2;
1101 			    }
1102 			    break;
1103 			}
1104 		    }
1105 		    if (!noquote)
1106 			netputs("\"");
1107 		    break;
1108 		}
1109 	    }
1110 	    break;
1111 
1112 #if	defined(AUTHENTICATION)
1113 	case TELOPT_AUTHENTICATION:
1114 	    netputs("AUTHENTICATION");
1115 
1116 	    if (length < 2) {
1117 		netputs(" (empty suboption??\?)");
1118 		break;
1119 	    }
1120 	    switch (pointer[1]) {
1121 	    case TELQUAL_REPLY:
1122 	    case TELQUAL_IS:
1123 		netputs((pointer[1] == TELQUAL_IS) ? " IS " : " REPLY ");
1124 		if (AUTHTYPE_NAME_OK(pointer[2]))
1125 		    netputs(AUTHTYPE_NAME(pointer[2]));
1126 		else
1127 		    netprintf(" %d ", pointer[2]);
1128 		if (length < 3) {
1129 		    netputs("(partial suboption??\?)");
1130 		    break;
1131 		}
1132 		netputs(((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
1133 			? "CLIENT|" : "SERVER|");
1134 		netputs(((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
1135 			? "MUTUAL" : "ONE-WAY");
1136 		netputs(((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
1137 			? "|ENCRYPT" : "");
1138 
1139 		auth_printsub(&pointer[1], length - 1, (unsigned char *)buf,
1140 			      sizeof(buf));
1141 		netputs(buf);
1142 		break;
1143 
1144 	    case TELQUAL_SEND:
1145 		i = 2;
1146 		netputs(" SEND ");
1147 		while (i < length) {
1148 		    if (AUTHTYPE_NAME_OK(pointer[i]))
1149 			netputs(AUTHTYPE_NAME(pointer[i]));
1150 		    else
1151 			netprintf("%d", pointer[i]);
1152 		    netputs(" ");
1153 		    if (++i >= length) {
1154 			netputs("(partial suboption??\?)");
1155 			break;
1156 		    }
1157 		    netputs(((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
1158 			    ? "CLIENT|" : "SERVER|");
1159 		    netputs(((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
1160 			    ? "MUTUAL" : "ONE-WAY");
1161 		    if ((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
1162 			netputs("|ENCRYPT");
1163 		    ++i;
1164 		}
1165 		break;
1166 
1167 	    case TELQUAL_NAME:
1168 		i = 2;
1169 		netputs(" NAME \"");
1170 		while (i < length) {
1171 		    if (isprint(pointer[i]))
1172 			netprintf("%c", pointer[i++]);
1173 		    else {
1174 			netprintf("\\%03o", pointer[i++]);
1175 		    }
1176 		}
1177 		netputs("\"");
1178 		break;
1179 
1180 	    default:
1181 		    for (i = 2; i < length; i++)
1182 			netprintf(" ?%d?", pointer[i]);
1183 		    break;
1184 	    }
1185 	    break;
1186 #endif
1187 
1188 #ifdef	ENCRYPTION
1189 	case TELOPT_ENCRYPT:
1190 	    netputs("ENCRYPT");
1191 	    if (length < 2) {
1192 		netputs(" (empty suboption??\?)");
1193 		break;
1194 	    }
1195 	    switch (pointer[1]) {
1196 	    case ENCRYPT_START:
1197 		netputs(" START");
1198 		break;
1199 
1200 	    case ENCRYPT_END:
1201 		netputs(" END");
1202 		break;
1203 
1204 	    case ENCRYPT_REQSTART:
1205 		netputs(" REQUEST-START");
1206 		break;
1207 
1208 	    case ENCRYPT_REQEND:
1209 		netputs(" REQUEST-END");
1210 		break;
1211 
1212 	    case ENCRYPT_IS:
1213 	    case ENCRYPT_REPLY:
1214 		netputs((pointer[1] == ENCRYPT_IS)
1215 			? " IS " : " REPLY ");
1216 		if (length < 3) {
1217 		    netputs(" (partial suboption??\?)");
1218 		    nfrontp += strlen(nfrontp);
1219 		    break;
1220 		}
1221 		if (ENCTYPE_NAME_OK(pointer[2]))
1222 		    netputs(ENCTYPE_NAME(pointer[2]));
1223 		else
1224 		    netprintf("%d (unknown)", pointer[2]);
1225 		netputs(" ");
1226 
1227 		encrypt_printsub(&pointer[1], length - 1,
1228 				 (unsigned char *) buf, sizeof(buf));
1229 		netputs(buf);
1230 		break;
1231 
1232 	    case ENCRYPT_SUPPORT:
1233 		i = 2;
1234 		netputs(" SUPPORT ");
1235 		nfrontp += strlen(nfrontp);
1236 		while (i < length) {
1237 		    if (ENCTYPE_NAME_OK(pointer[i]))
1238 			netputs(ENCTYPE_NAME(pointer[i]));
1239 		    else
1240 			netprintf("%d", pointer[i]);
1241 		    netputs(" ");
1242 		    i++;
1243 		}
1244 		break;
1245 
1246 	    case ENCRYPT_ENC_KEYID:
1247 		netputs(" ENC_KEYID");
1248 		goto encommon;
1249 
1250 	    case ENCRYPT_DEC_KEYID:
1251 		netputs(" DEC_KEYID");
1252 		goto encommon;
1253 
1254 	    default:
1255 		netprintf(" %d (unknown)", pointer[1]);
1256 	    encommon:
1257 		for (i = 2; i < length; i++)
1258 		    netprintf(" %d", pointer[i]);
1259 		break;
1260 	    }
1261 	    break;
1262 #endif	/* ENCRYPTION */
1263 
1264 	default:
1265 	    if (TELOPT_OK(pointer[0]))
1266 	        netputs(TELOPT(pointer[0]));
1267 	    else
1268 	        netprintf("%d", pointer[0]);
1269 	    netputs(" (unknown)");
1270 	    for (i = 1; i < length; i++)
1271 		netprintf(" %d", pointer[i]);
1272 	    break;
1273 	}
1274 	netputs("\r\n");
1275 }
1276 
1277 /*
1278  * Dump a data buffer in hex and ascii to the output data stream.
1279  */
1280 	void
printdata(tag,ptr,cnt)1281 printdata(tag, ptr, cnt)
1282 	register char *tag;
1283 	register char *ptr;
1284 	register int cnt;
1285 {
1286 	register int i;
1287 	char xbuf[30];
1288 
1289 	while (cnt) {
1290 		/* add a line of output */
1291 		netputs(tag);
1292 		netputs(": ");
1293 		for (i = 0; i < 20 && cnt; i++) {
1294 			netprintf(nfrontp, "%02x", *ptr);
1295 			nfrontp += strlen(nfrontp);
1296 			if (isprint((int) *ptr)) {
1297 				xbuf[i] = *ptr;
1298 			} else {
1299 				xbuf[i] = '.';
1300 			}
1301 			if (i % 2)
1302 				netputs(" ");
1303 			cnt--;
1304 			ptr++;
1305 		}
1306 		xbuf[i] = '\0';
1307 		netputs(" ");
1308 		netputs(xbuf);
1309 		netputs("\r\n");
1310 	}
1311 }
1312 #endif /* DIAGNOSTICS */
1313