Home | History | Annotate | Download | only in telnet
      1 /*
      2  * Copyright 1994-2002 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /*
      9  * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c
     10  */
     11 
     12 /*
     13  * Copyright (c) 1988, 1993
     14  *	The Regents of the University of California.  All rights reserved.
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in the
     23  *    documentation and/or other materials provided with the distribution.
     24  * 3. All advertising materials mentioning features or use of this software
     25  *    must display the following acknowledgement:
     26  *	This product includes software developed by the University of
     27  *	California, Berkeley and its contributors.
     28  * 4. Neither the name of the University nor the names of its contributors
     29  *    may be used to endorse or promote products derived from this software
     30  *    without specific prior written permission.
     31  *
     32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     42  * SUCH DAMAGE.
     43  */
     44 
     45 #ifndef lint
     46 static char sccsid[] = "@(#)utilities.c	8.1 (Berkeley) 6/6/93";
     47 #endif /* not lint */
     48 
     49 #define	TELOPTS
     50 #ifdef	lint
     51 static char *telcmds[] = {0};
     52 static char *slc_names[] = {0};
     53 static char *encrypt_names[] = {0};
     54 static char *enctype_names[] = {0};
     55 #else	/* lint */
     56 #define	TELCMDS
     57 #define	SLC_NAMES
     58 #endif	/* lint */
     59 #include <arpa/telnet.h>
     60 #include <sys/types.h>
     61 #include <sys/time.h>
     62 #include <sys/param.h>
     63 #include <sys/socket.h>
     64 #include <errno.h>
     65 
     66 #include <ctype.h>
     67 
     68 #include "general.h"
     69 
     70 #include "ring.h"
     71 
     72 #include "defines.h"
     73 
     74 #include "externs.h"
     75 
     76 FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
     77 int	prettydump;
     78 
     79 /*
     80  * upcase()
     81  *
     82  *	Upcase (in place) the argument.
     83  */
     84 
     85     void
     86 upcase(argument)
     87 	register char *argument;
     88 {
     89 	register int c;
     90 
     91 	while ((c = *argument) != 0) {
     92 		if (islower(c)) {
     93 			*argument = toupper(c);
     94 		}
     95 	argument++;
     96 	}
     97 }
     98 
     99 /*
    100  * SetSockOpt()
    101  *
    102  * Compensate for differences in 4.2 and 4.3 systems.
    103  */
    104 
    105     int
    106 SetSockOpt(fd, level, option, yesno)
    107     int fd, level, option, yesno;
    108 {
    109 	return (setsockopt(fd, level, option, &yesno, sizeof (yesno)));
    110 }
    111 
    112 /*
    113  * The following are routines used to print out debugging information.
    114  */
    115 
    116 unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)";
    117 
    118     void
    119 SetNetTrace(file)
    120     register char *file;
    121 {
    122 	if (NetTrace && NetTrace != stdout)
    123 		(void) fclose(NetTrace);
    124 	if (file && (strcmp(file, "-") != 0)) {
    125 		NetTrace = fopen(file, "w");
    126 		if (NetTrace) {
    127 			(void) strcpy((char *)NetTraceFile, file);
    128 			return;
    129 		}
    130 		(void) fprintf(stderr, "Cannot open %s.\n", file);
    131 	}
    132 	NetTrace = stdout;
    133 	(void) strcpy((char *)NetTraceFile, "(standard output)");
    134 }
    135 
    136     void
    137 Dump(direction, buffer, length)
    138     char direction;
    139     unsigned char *buffer;
    140     int length;
    141 {
    142 #define	BYTES_PER_LINE	32
    143 #define	min(x, y)	((x < y) ? x:y)
    144 	unsigned char *pThis;
    145 	int offset;
    146 
    147 	offset = 0;
    148 
    149 	while (length) {
    150 		/* print one line */
    151 		(void) fprintf(NetTrace, "%c 0x%x\t", direction, offset);
    152 		pThis = buffer;
    153 		if (prettydump) {
    154 			buffer = buffer + min(length, BYTES_PER_LINE/2);
    155 			while (pThis < buffer) {
    156 				(void) fprintf(NetTrace, "%c%.2x",
    157 				    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
    158 				    (*pThis)&0xff);
    159 				pThis++;
    160 			}
    161 			length -= BYTES_PER_LINE/2;
    162 			offset += BYTES_PER_LINE/2;
    163 		} else {
    164 			buffer = buffer + min(length, BYTES_PER_LINE);
    165 			while (pThis < buffer) {
    166 				(void) fprintf(NetTrace, "%.2x", (*pThis)&0xff);
    167 				pThis++;
    168 			}
    169 			length -= BYTES_PER_LINE;
    170 			offset += BYTES_PER_LINE;
    171 		}
    172 		if (NetTrace == stdout) {
    173 			(void) fprintf(NetTrace, "\r\n");
    174 		} else {
    175 			(void) fprintf(NetTrace, "\n");
    176 		}
    177 		if (length < 0) {
    178 			(void) fflush(NetTrace);
    179 			return;
    180 		}
    181 		/* find next unique line */
    182 	}
    183 	(void) fflush(NetTrace);
    184 }
    185 
    186 
    187 	void
    188 printoption(direction, cmd, option)
    189 	char *direction;
    190 	int cmd, option;
    191 {
    192 	if (!showoptions)
    193 		return;
    194 	if (cmd == IAC) {
    195 		if (TELCMD_OK(option))
    196 			(void) fprintf(NetTrace, "%s IAC %s", direction,
    197 			    TELCMD(option));
    198 		else
    199 			(void) fprintf(NetTrace, "%s IAC %d", direction,
    200 				option);
    201 	} else {
    202 		register char *fmt;
    203 		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
    204 			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
    205 		if (fmt) {
    206 		    (void) fprintf(NetTrace, "%s %s ", direction, fmt);
    207 		    if (TELOPT_OK(option))
    208 			(void) fprintf(NetTrace, "%s", TELOPT(option));
    209 		    else if (option == TELOPT_EXOPL)
    210 			(void) fprintf(NetTrace, "EXOPL");
    211 		    else
    212 			(void) fprintf(NetTrace, "%d", option);
    213 		} else
    214 			(void) fprintf(NetTrace, "%s %d %d", direction, cmd,
    215 			    option);
    216 	}
    217 	if (NetTrace == stdout) {
    218 	    (void) fprintf(NetTrace, "\r\n");
    219 	    (void) fflush(NetTrace);
    220 	} else {
    221 	    (void) fprintf(NetTrace, "\n");
    222 	}
    223 }
    224 
    225     void
    226 optionstatus()
    227 {
    228 	register int i;
    229 	extern char will_wont_resp[], do_dont_resp[];
    230 
    231 	for (i = 0; i < SUBBUFSIZE; i++) {
    232 		if (do_dont_resp[i]) {
    233 			if (TELOPT_OK(i))
    234 				(void) printf("resp DO_DONT %s: %d\n",
    235 				    TELOPT(i), do_dont_resp[i]);
    236 			else if (TELCMD_OK(i))
    237 				(void) printf("resp DO_DONT %s: %d\n",
    238 				    TELCMD(i), do_dont_resp[i]);
    239 			else
    240 				(void) printf("resp DO_DONT %d: %d\n", i,
    241 				    do_dont_resp[i]);
    242 			if (my_want_state_is_do(i)) {
    243 				if (TELOPT_OK(i))
    244 					(void) printf("want DO   %s\n",
    245 					    TELOPT(i));
    246 				else if (TELCMD_OK(i))
    247 					(void) printf("want DO   %s\n",
    248 						TELCMD(i));
    249 				else
    250 					(void) printf("want DO   %d\n", i);
    251 			} else {
    252 				if (TELOPT_OK(i))
    253 					(void) printf("want DONT %s\n",
    254 					    TELOPT(i));
    255 				else if (TELCMD_OK(i))
    256 					(void) printf("want DONT %s\n",
    257 					    TELCMD(i));
    258 				else
    259 					(void) printf("want DONT %d\n", i);
    260 			}
    261 		} else {
    262 			if (my_state_is_do(i)) {
    263 				if (TELOPT_OK(i))
    264 					(void) printf("     DO   %s\n",
    265 					    TELOPT(i));
    266 				else if (TELCMD_OK(i))
    267 					(void) printf("     DO   %s\n",
    268 					    TELCMD(i));
    269 				else
    270 					(void) printf("     DO   %d\n", i);
    271 			}
    272 		}
    273 		if (will_wont_resp[i]) {
    274 			if (TELOPT_OK(i))
    275 				(void) printf("resp WILL_WONT %s: %d\n",
    276 				    TELOPT(i), will_wont_resp[i]);
    277 			else if (TELCMD_OK(i))
    278 				(void) printf("resp WILL_WONT %s: %d\n",
    279 				    TELCMD(i), will_wont_resp[i]);
    280 			else
    281 				(void) printf("resp WILL_WONT %d: %d\n",
    282 				    i, will_wont_resp[i]);
    283 			if (my_want_state_is_will(i)) {
    284 				if (TELOPT_OK(i))
    285 					(void) printf("want WILL %s\n",
    286 					    TELOPT(i));
    287 				else if (TELCMD_OK(i))
    288 					(void) printf("want WILL %s\n",
    289 					    TELCMD(i));
    290 				else
    291 					(void) printf("want WILL %d\n", i);
    292 			} else {
    293 				if (TELOPT_OK(i))
    294 					(void) printf("want WONT %s\n",
    295 					    TELOPT(i));
    296 				else if (TELCMD_OK(i))
    297 					(void) printf("want WONT %s\n",
    298 					    TELCMD(i));
    299 				else
    300 					(void) printf("want WONT %d\n", i);
    301 			}
    302 		} else {
    303 			if (my_state_is_will(i)) {
    304 				if (TELOPT_OK(i))
    305 					(void) printf("     WILL %s\n",
    306 					    TELOPT(i));
    307 				else if (TELCMD_OK(i))
    308 					(void) printf("     WILL %s\n",
    309 					    TELCMD(i));
    310 				else
    311 					(void) printf("     WILL %d\n", i);
    312 			}
    313 		}
    314 	}
    315 
    316 }
    317 
    318     void
    319 printsub(direction, pointer, length)
    320 	char direction;	/* '<' or '>' */
    321 	unsigned char *pointer;	/* where suboption data sits */
    322 	int	  length;	/* length of suboption data */
    323 {
    324 	register int i;
    325 	char buf[512];
    326 	extern int want_status_response;
    327 
    328 	if (showoptions || direction == 0 ||
    329 	    (want_status_response && (pointer[0] == TELOPT_STATUS))) {
    330 		if (direction) {
    331 			(void) fprintf(NetTrace, "%s IAC SB ",
    332 				(direction == '<')? "RCVD":"SENT");
    333 			if (length >= 3) {
    334 				register int j;
    335 
    336 				i = pointer[length-2];
    337 				j = pointer[length-1];
    338 
    339 				if (i != IAC || j != SE) {
    340 					(void) fprintf(NetTrace,
    341 					    "(terminated by ");
    342 					if (TELOPT_OK(i))
    343 						(void) fprintf(NetTrace, "%s ",
    344 						    TELOPT(i));
    345 					else if (TELCMD_OK(i))
    346 						(void) fprintf(NetTrace, "%s ",
    347 						    TELCMD(i));
    348 					else
    349 						(void) fprintf(NetTrace, "%d ",
    350 						    i);
    351 					if (TELOPT_OK(j))
    352 						(void) fprintf(NetTrace, "%s",
    353 						    TELOPT(j));
    354 					else if (TELCMD_OK(j))
    355 						(void) fprintf(NetTrace, "%s",
    356 						    TELCMD(j));
    357 					else
    358 						(void) fprintf(NetTrace, "%d",
    359 						    j);
    360 					(void) fprintf(NetTrace,
    361 					    ", not IAC SE!) ");
    362 				}
    363 			}
    364 			length -= 2;
    365 		}
    366 		if (length < 1) {
    367 			(void) fprintf(NetTrace, "(Empty suboption??\?)");
    368 			if (NetTrace == stdout)
    369 				(void) fflush(NetTrace);
    370 			return;
    371 		}
    372 		switch (pointer[0]) {
    373 		case TELOPT_TTYPE:
    374 			(void) fprintf(NetTrace, "TERMINAL-TYPE ");
    375 			switch (pointer[1]) {
    376 			case TELQUAL_IS:
    377 				(void) fprintf(NetTrace, "IS \"%.*s\"",
    378 				    length-2,
    379 				    (char *)pointer+2);
    380 				break;
    381 			case TELQUAL_SEND:
    382 				(void) fprintf(NetTrace, "SEND");
    383 				break;
    384 			default:
    385 				(void) fprintf(NetTrace,
    386 				    "- unknown qualifier %d (0x%x).",
    387 				    pointer[1], pointer[1]);
    388 			}
    389 			break;
    390 		case TELOPT_TSPEED:
    391 			(void) fprintf(NetTrace, "TERMINAL-SPEED");
    392 			if (length < 2) {
    393 				(void) fprintf(NetTrace,
    394 				    " (empty suboption??\?)");
    395 				break;
    396 			}
    397 			switch (pointer[1]) {
    398 			case TELQUAL_IS:
    399 				(void) fprintf(NetTrace, " IS ");
    400 				(void) fprintf(NetTrace, "%.*s", length-2,
    401 				    (char *)pointer+2);
    402 				break;
    403 			default:
    404 				if (pointer[1] == 1)
    405 					(void) fprintf(NetTrace, " SEND");
    406 				else
    407 					(void) fprintf(NetTrace,
    408 					    " %d (unknown)", pointer[1]);
    409 				for (i = 2; i < length; i++)
    410 					(void) fprintf(NetTrace, " ?%d?",
    411 					    pointer[i]);
    412 				break;
    413 			}
    414 			break;
    415 
    416 		case TELOPT_LFLOW:
    417 			(void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
    418 			if (length < 2) {
    419 				(void) fprintf(NetTrace,
    420 				    " (empty suboption??\?)");
    421 				break;
    422 			}
    423 			switch (pointer[1]) {
    424 			case LFLOW_OFF:
    425 				(void) fprintf(NetTrace, " OFF");
    426 				break;
    427 			case LFLOW_ON:
    428 				(void) fprintf(NetTrace, " ON");
    429 				break;
    430 			case LFLOW_RESTART_ANY:
    431 				(void) fprintf(NetTrace, " RESTART-ANY");
    432 				break;
    433 			case LFLOW_RESTART_XON:
    434 				(void) fprintf(NetTrace, " RESTART-XON");
    435 				break;
    436 			default:
    437 				(void) fprintf(NetTrace, " %d (unknown)",
    438 				    pointer[1]);
    439 			}
    440 			for (i = 2; i < length; i++)
    441 				(void) fprintf(NetTrace, " ?%d?",
    442 				    pointer[i]);
    443 			break;
    444 
    445 		case TELOPT_NAWS:
    446 			(void) fprintf(NetTrace, "NAWS");
    447 			if (length < 2) {
    448 				(void) fprintf(NetTrace,
    449 				    " (empty suboption??\?)");
    450 				break;
    451 			}
    452 			if (length == 2) {
    453 				(void) fprintf(NetTrace, " ?%d?", pointer[1]);
    454 				break;
    455 			}
    456 			(void) fprintf(NetTrace, " %d %d (%d)",
    457 			    pointer[1], pointer[2],
    458 			    (int)((((unsigned int)pointer[1])<<8)|
    459 			    ((unsigned int)pointer[2])));
    460 			if (length == 4) {
    461 				(void) fprintf(NetTrace, " ?%d?", pointer[3]);
    462 				break;
    463 			}
    464 			(void) fprintf(NetTrace, " %d %d (%d)",
    465 			    pointer[3], pointer[4],
    466 			    (int)((((unsigned int)pointer[3])<<8)|
    467 			    ((unsigned int)pointer[4])));
    468 			for (i = 5; i < length; i++)
    469 				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
    470 			break;
    471 
    472 		case TELOPT_AUTHENTICATION:
    473 			(void) fprintf(NetTrace, "AUTHENTICATION");
    474 			if (length < 2) {
    475 				(void) fprintf(NetTrace,
    476 					" (empty suboption??\?)");
    477 				break;
    478 			}
    479 			switch (pointer[1]) {
    480 			case TELQUAL_REPLY:
    481 			case TELQUAL_IS:
    482 				(void) fprintf(NetTrace, " %s ",
    483 				    (pointer[1] == TELQUAL_IS) ?
    484 				    "IS" : "REPLY");
    485 				if (AUTHTYPE_NAME_OK(pointer[2]))
    486 					(void) fprintf(NetTrace, "%s ",
    487 					    AUTHTYPE_NAME(pointer[2]));
    488 				else
    489 					(void) fprintf(NetTrace, "%d ",
    490 						pointer[2]);
    491 				if (length < 3) {
    492 					(void) fprintf(NetTrace,
    493 					    "(partial suboption??\?)");
    494 					break;
    495 				}
    496 				(void) fprintf(NetTrace, "%s|%s",
    497 				    ((pointer[3] & AUTH_WHO_MASK) ==
    498 				    AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER",
    499 				    ((pointer[3] & AUTH_HOW_MASK) ==
    500 				    AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY");
    501 
    502 				auth_printsub(&pointer[1], length - 1,
    503 				    (uchar_t *)buf, sizeof (buf));
    504 				(void) fprintf(NetTrace, "%s", buf);
    505 				break;
    506 
    507 			case TELQUAL_SEND:
    508 				i = 2;
    509 				(void) fprintf(NetTrace, " SEND ");
    510 				while (i < length) {
    511 					if (AUTHTYPE_NAME_OK(pointer[i]))
    512 						(void) fprintf(NetTrace, "%s ",
    513 						    AUTHTYPE_NAME(pointer[i]));
    514 					else
    515 						(void) fprintf(NetTrace, "%d ",
    516 						    pointer[i]);
    517 					if (++i >= length) {
    518 						(void) fprintf(NetTrace,
    519 						    "(partial "
    520 						    "suboption??\?)");
    521 						break;
    522 					}
    523 					(void) fprintf(NetTrace, "%s|%s ",
    524 					    ((pointer[i] & AUTH_WHO_MASK) ==
    525 					    AUTH_WHO_CLIENT) ?
    526 					    "CLIENT" : "SERVER",
    527 					    ((pointer[i] & AUTH_HOW_MASK) ==
    528 					    AUTH_HOW_MUTUAL) ?
    529 					    "MUTUAL" : "ONE-WAY");
    530 					++i;
    531 				}
    532 				break;
    533 
    534 			case TELQUAL_NAME:
    535 				i = 2;
    536 				(void) fprintf(NetTrace, " NAME \"");
    537 				while (i < length)
    538 					(void) putc(pointer[i++], NetTrace);
    539 				(void) putc('"', NetTrace);
    540 				break;
    541 
    542 			default:
    543 				for (i = 2; i < length; i++)
    544 				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
    545 				break;
    546 			}
    547 			break;
    548 
    549 		case TELOPT_ENCRYPT:
    550 			(void) fprintf(NetTrace, "ENCRYPT");
    551 			if (length < 2) {
    552 				(void) fprintf(NetTrace,
    553 				    " (empty suboption??\?)");
    554 				break;
    555 			}
    556 			switch (pointer[1]) {
    557 			case ENCRYPT_START:
    558 				(void) fprintf(NetTrace, " START");
    559 				break;
    560 
    561 			case ENCRYPT_END:
    562 				(void) fprintf(NetTrace, " END");
    563 				break;
    564 
    565 			case ENCRYPT_REQSTART:
    566 				(void) fprintf(NetTrace, " REQUEST-START");
    567 				break;
    568 
    569 			case ENCRYPT_REQEND:
    570 				(void) fprintf(NetTrace, " REQUEST-END");
    571 				break;
    572 
    573 			case ENCRYPT_IS:
    574 			case ENCRYPT_REPLY:
    575 				(void) fprintf(NetTrace, " %s ",
    576 				    (pointer[1] == ENCRYPT_IS) ?
    577 				    "IS" : "REPLY");
    578 				if (length < 3) {
    579 					(void) fprintf(NetTrace, " (partial "
    580 					    "suboption??\?)");
    581 					break;
    582 				}
    583 				if (ENCTYPE_NAME_OK(pointer[2]))
    584 					(void) fprintf(NetTrace, "%s ",
    585 					    ENCTYPE_NAME(pointer[2]));
    586 				else
    587 					(void) fprintf(NetTrace,
    588 					    " %d (unknown)", pointer[2]);
    589 
    590 				encrypt_printsub(&pointer[1], length - 1,
    591 				    (uchar_t *)buf, sizeof (buf));
    592 				(void) fprintf(NetTrace, "%s", buf);
    593 				break;
    594 
    595 			case ENCRYPT_SUPPORT:
    596 				i = 2;
    597 				(void) fprintf(NetTrace, " SUPPORT ");
    598 				while (i < length) {
    599 					if (ENCTYPE_NAME_OK(pointer[i]))
    600 						(void) fprintf(NetTrace, "%s ",
    601 						    ENCTYPE_NAME(pointer[i]));
    602 					else
    603 						(void) fprintf(NetTrace, "%d ",
    604 						    pointer[i]);
    605 					i++;
    606 				}
    607 				break;
    608 
    609 			case ENCRYPT_ENC_KEYID:
    610 				(void) fprintf(NetTrace, " ENC_KEYID ");
    611 				goto encommon;
    612 
    613 			case ENCRYPT_DEC_KEYID:
    614 				(void) fprintf(NetTrace, " DEC_KEYID ");
    615 				goto encommon;
    616 
    617 			default:
    618 				(void) fprintf(NetTrace, " %d (unknown)",
    619 				    pointer[1]);
    620 			encommon:
    621 				for (i = 2; i < length; i++)
    622 					(void) fprintf(NetTrace, " %d",
    623 					    pointer[i]);
    624 				break;
    625 			}
    626 			break;
    627 
    628 		case TELOPT_LINEMODE:
    629 			(void) fprintf(NetTrace, "LINEMODE ");
    630 			if (length < 2) {
    631 				(void) fprintf(NetTrace,
    632 				    " (empty suboption??\?)");
    633 				break;
    634 			}
    635 			switch (pointer[1]) {
    636 			case WILL:
    637 				(void) fprintf(NetTrace, "WILL ");
    638 				goto common;
    639 			case WONT:
    640 				(void) fprintf(NetTrace, "WONT ");
    641 				goto common;
    642 			case DO:
    643 				(void) fprintf(NetTrace, "DO ");
    644 				goto common;
    645 			case DONT:
    646 				(void) fprintf(NetTrace, "DONT ");
    647 common:
    648 				if (length < 3) {
    649 					(void) fprintf(NetTrace,
    650 						"(no option??\?)");
    651 					break;
    652 				}
    653 				switch (pointer[2]) {
    654 				case LM_FORWARDMASK:
    655 					(void) fprintf(NetTrace,
    656 					    "Forward Mask");
    657 					for (i = 3; i < length; i++)
    658 						(void) fprintf(NetTrace, " %x",
    659 						    pointer[i]);
    660 					break;
    661 				default:
    662 					(void) fprintf(NetTrace, "%d (unknown)",
    663 					    pointer[2]);
    664 					for (i = 3; i < length; i++)
    665 					(void) fprintf(NetTrace,
    666 					    " %d", pointer[i]);
    667 					break;
    668 				}
    669 				break;
    670 
    671 			case LM_SLC:
    672 				(void) fprintf(NetTrace, "SLC");
    673 				for (i = 2; i < length - 2; i += 3) {
    674 					if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
    675 						(void) fprintf(NetTrace, " %s",
    676 						    SLC_NAME(pointer[
    677 						    i+SLC_FUNC]));
    678 					else
    679 						(void) fprintf(NetTrace, " %d",
    680 						    pointer[i+SLC_FUNC]);
    681 					switch (pointer[i+SLC_FLAGS] &
    682 					    SLC_LEVELBITS) {
    683 					case SLC_NOSUPPORT:
    684 						(void) fprintf(NetTrace,
    685 						    " NOSUPPORT");
    686 						break;
    687 					case SLC_CANTCHANGE:
    688 						(void) fprintf(NetTrace,
    689 						    " CANTCHANGE");
    690 						break;
    691 					case SLC_VARIABLE:
    692 						(void) fprintf(NetTrace,
    693 						    " VARIABLE");
    694 						break;
    695 					case SLC_DEFAULT:
    696 						(void) fprintf(NetTrace,
    697 						    " DEFAULT");
    698 						break;
    699 					}
    700 					(void) fprintf(NetTrace, "%s%s%s",
    701 					    pointer[i+SLC_FLAGS]&SLC_ACK ?
    702 						"|ACK" : "",
    703 					    pointer[i+SLC_FLAGS]&SLC_FLUSHIN ?
    704 						"|FLUSHIN" : "",
    705 					    pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ?
    706 						"|FLUSHOUT" : "");
    707 					if (pointer[i+SLC_FLAGS] &
    708 					    ~(SLC_ACK|SLC_FLUSHIN|
    709 					    SLC_FLUSHOUT| SLC_LEVELBITS))
    710 					(void) fprintf(NetTrace, "(0x%x)",
    711 					    pointer[i+SLC_FLAGS]);
    712 					(void) fprintf(NetTrace, " %d;",
    713 					    pointer[i+SLC_VALUE]);
    714 					if ((pointer[i+SLC_VALUE] == IAC) &&
    715 					    (pointer[i+SLC_VALUE+1] == IAC))
    716 						i++;
    717 				}
    718 				for (; i < length; i++)
    719 					(void) fprintf(NetTrace, " ?%d?",
    720 					    pointer[i]);
    721 				break;
    722 
    723 			case LM_MODE:
    724 				(void) fprintf(NetTrace, "MODE ");
    725 				if (length < 3) {
    726 					(void) fprintf(NetTrace,
    727 					    "(no mode??\?)");
    728 					break;
    729 				}
    730 				{
    731 					char tbuf[64];
    732 					(void) sprintf(tbuf, "%s%s%s%s%s",
    733 					    pointer[2]&MODE_EDIT ? "|EDIT" : "",
    734 					    pointer[2]&MODE_TRAPSIG ?
    735 					    "|TRAPSIG" : "",
    736 					    pointer[2]&MODE_SOFT_TAB ?
    737 					    "|SOFT_TAB" : "",
    738 					    pointer[2]&MODE_LIT_ECHO ?
    739 					    "|LIT_ECHO" : "",
    740 					    pointer[2]&MODE_ACK ? "|ACK" : "");
    741 					(void) fprintf(NetTrace, "%s", tbuf[1] ?
    742 					    &tbuf[1] : "0");
    743 				}
    744 				if (pointer[2]&~(MODE_MASK))
    745 					(void) fprintf(NetTrace, " (0x%x)",
    746 					    pointer[2]);
    747 				for (i = 3; i < length; i++)
    748 					(void) fprintf(NetTrace, " ?0x%x?",
    749 					    pointer[i]);
    750 				break;
    751 			default:
    752 				(void) fprintf(NetTrace, "%d (unknown)",
    753 				    pointer[1]);
    754 				for (i = 2; i < length; i++)
    755 					(void) fprintf(NetTrace, " %d",
    756 					    pointer[i]);
    757 				}
    758 				break;
    759 
    760 		case TELOPT_STATUS: {
    761 				register char *cp;
    762 				register int j, k;
    763 
    764 				(void) fprintf(NetTrace, "STATUS");
    765 
    766 				switch (pointer[1]) {
    767 				default:
    768 					if (pointer[1] == TELQUAL_SEND)
    769 						(void) fprintf(NetTrace,
    770 						    " SEND");
    771 					else
    772 						(void) fprintf(NetTrace,
    773 						    " %d (unknown)",
    774 						    pointer[1]);
    775 					for (i = 2; i < length; i++)
    776 					(void) fprintf(NetTrace, " ?%d?",
    777 					    pointer[i]);
    778 					break;
    779 				case TELQUAL_IS:
    780 					if (--want_status_response < 0)
    781 						want_status_response = 0;
    782 					if (NetTrace == stdout)
    783 						(void) fprintf(NetTrace,
    784 						    " IS\r\n");
    785 					else
    786 						(void) fprintf(NetTrace,
    787 						    " IS\n");
    788 
    789 					for (i = 2; i < length; i++) {
    790 						switch (pointer[i]) {
    791 						case DO:
    792 							cp = "DO";
    793 							goto common2;
    794 						case DONT:
    795 							cp = "DONT";
    796 							goto common2;
    797 						case WILL:
    798 							cp = "WILL";
    799 							goto common2;
    800 						case WONT:
    801 							cp = "WONT";
    802 							goto common2;
    803 common2:
    804 							i++;
    805 							if (TELOPT_OK(
    806 							    (int)pointer[i]))
    807 								(void) fprintf(
    808 								    NetTrace,
    809 								    " %s %s",
    810 								    cp,
    811 								    TELOPT(
    812 								    pointer[
    813 								    i]));
    814 							else
    815 								(void) fprintf(
    816 								    NetTrace,
    817 								    " %s %d",
    818 								    cp,
    819 								    pointer[i]);
    820 
    821 							if (NetTrace == stdout)
    822 								(void) fprintf(
    823 								    NetTrace,
    824 								    "\r\n");
    825 							else
    826 								(void) fprintf(
    827 								    NetTrace,
    828 								    "\n");
    829 							break;
    830 
    831 						case SB:
    832 							(void) fprintf(NetTrace,
    833 							    " SB ");
    834 							i++;
    835 							j = k = i;
    836 							while (j < length) {
    837 			if (pointer[j] == SE) {
    838 				if (j+1 == length)
    839 					break;
    840 				if (pointer[j+1] == SE)
    841 					j++;
    842 				else
    843 					break;
    844 				}
    845 				pointer[k++] = pointer[j++];
    846 							}
    847 							printsub(0,
    848 							    &pointer[i], k - i);
    849 							if (i < length) {
    850 						(void) fprintf(NetTrace, " SE");
    851 				i = j;
    852 			} else
    853 				i = j - 1;
    854 
    855 			if (NetTrace == stdout)
    856 				(void) fprintf(NetTrace, "\r\n");
    857 			else
    858 				(void) fprintf(NetTrace, "\n");
    859 
    860 							break;
    861 
    862 						default:
    863 							(void) fprintf(NetTrace,
    864 							    " %d", pointer[i]);
    865 							break;
    866 						}
    867 					}
    868 					break;
    869 				}
    870 				break;
    871 			}
    872 
    873 		case TELOPT_XDISPLOC:
    874 			(void) fprintf(NetTrace, "X-DISPLAY-LOCATION ");
    875 			switch (pointer[1]) {
    876 			case TELQUAL_IS:
    877 				(void) fprintf(NetTrace, "IS \"%.*s\"",
    878 				    length-2, (char *)pointer+2);
    879 				break;
    880 			case TELQUAL_SEND:
    881 				(void) fprintf(NetTrace, "SEND");
    882 				break;
    883 			default:
    884 				(void) fprintf(NetTrace,
    885 				    "- unknown qualifier %d (0x%x).",
    886 				    pointer[1], pointer[1]);
    887 			}
    888 			break;
    889 
    890 		case TELOPT_NEW_ENVIRON:
    891 	    (void) fprintf(NetTrace, "NEW-ENVIRON ");
    892 #ifdef	OLD_ENVIRON
    893 	    goto env_common1;
    894 	case TELOPT_OLD_ENVIRON:
    895 	    (void) fprintf(NetTrace, "OLD-ENVIRON ");
    896 	env_common1:
    897 #endif
    898 	    switch (pointer[1]) {
    899 	    case TELQUAL_IS:
    900 		(void) fprintf(NetTrace, "IS ");
    901 		goto env_common;
    902 	    case TELQUAL_SEND:
    903 		(void) fprintf(NetTrace, "SEND ");
    904 		goto env_common;
    905 	    case TELQUAL_INFO:
    906 		(void) fprintf(NetTrace, "INFO ");
    907 	    env_common:
    908 		{
    909 		    register int noquote = 2;
    910 #if defined(ENV_HACK) && defined(OLD_ENVIRON)
    911 		    extern int old_env_var, old_env_value;
    912 #endif
    913 		    for (i = 2; i < length; i++) {
    914 			switch (pointer[i]) {
    915 			case NEW_ENV_VALUE:
    916 #ifdef OLD_ENVIRON
    917 		    /*	case NEW_ENV_OVAR: */
    918 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
    919 #ifdef	ENV_HACK
    920 				if (old_env_var == OLD_ENV_VALUE)
    921 					(void) fprintf(NetTrace,
    922 					    "\" (VALUE) " + noquote);
    923 				else
    924 #endif
    925 					(void) fprintf(NetTrace,
    926 					    "\" VAR " + noquote);
    927 			    } else
    928 #endif /* OLD_ENVIRON */
    929 				(void) fprintf(NetTrace, "\" VALUE " + noquote);
    930 			    noquote = 2;
    931 			    break;
    932 
    933 			case NEW_ENV_VAR:
    934 #ifdef OLD_ENVIRON
    935 		    /* case OLD_ENV_VALUE: */
    936 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
    937 #ifdef	ENV_HACK
    938 				if (old_env_value == OLD_ENV_VAR)
    939 					(void) fprintf(NetTrace,
    940 					    "\" (VAR) " + noquote);
    941 				else
    942 #endif
    943 					(void) fprintf(NetTrace,
    944 					    "\" VALUE " + noquote);
    945 			    } else
    946 #endif /* OLD_ENVIRON */
    947 				(void) fprintf(NetTrace, "\" VAR " + noquote);
    948 			    noquote = 2;
    949 			    break;
    950 
    951 			case ENV_ESC:
    952 			    (void) fprintf(NetTrace, "\" ESC " + noquote);
    953 			    noquote = 2;
    954 			    break;
    955 
    956 			case ENV_USERVAR:
    957 			    (void) fprintf(NetTrace, "\" USERVAR " + noquote);
    958 			    noquote = 2;
    959 			    break;
    960 
    961 			default:
    962 			def_case:
    963 			    if (isprint(pointer[i]) && pointer[i] != '"') {
    964 				if (noquote) {
    965 				    (void) putc('"', NetTrace);
    966 				    noquote = 0;
    967 				}
    968 				(void) putc(pointer[i], NetTrace);
    969 			    } else {
    970 				(void) fprintf(NetTrace, "\" %03o " + noquote,
    971 							pointer[i]);
    972 				noquote = 2;
    973 			    }
    974 			    break;
    975 			}
    976 		    }
    977 		    if (!noquote)
    978 			(void) putc('"', NetTrace);
    979 		    break;
    980 		}
    981 	    }
    982 	    break;
    983 
    984 	default:
    985 	    if (TELOPT_OK(pointer[0]))
    986 		(void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
    987 	    else
    988 		(void) fprintf(NetTrace, "%d (unknown)", pointer[0]);
    989 	    for (i = 1; i < length; i++)
    990 		(void) fprintf(NetTrace, " %d", pointer[i]);
    991 	    break;
    992 	}
    993 	if (direction) {
    994 	    if (NetTrace == stdout)
    995 		(void) fprintf(NetTrace, "\r\n");
    996 	    else
    997 		(void) fprintf(NetTrace, "\n");
    998 	}
    999 	if (NetTrace == stdout)
   1000 	    (void) fflush(NetTrace);
   1001 	}
   1002 }
   1003 
   1004 /*
   1005  * EmptyTerminal - called to make sure that the terminal buffer is empty.
   1006  *			Note that we consider the buffer to run all the
   1007  *			way to the kernel (thus the select).
   1008  */
   1009 
   1010 static void
   1011 EmptyTerminal()
   1012 {
   1013 	fd_set	o;
   1014 
   1015 	FD_ZERO(&o);
   1016 
   1017 	if (TTYBYTES() == 0) {
   1018 		FD_SET(tout, &o);
   1019 		/* wait for TTLOWAT */
   1020 		(void) select(tout+1, NULL, &o, NULL, NULL);
   1021 	} else {
   1022 		while (TTYBYTES()) {
   1023 			if (ttyflush(0) == -2) {
   1024 				/* This will not return. */
   1025 				fatal_tty_error("write");
   1026 			}
   1027 			FD_SET(tout, &o);
   1028 			/* wait for TTLOWAT */
   1029 			(void) select(tout+1, NULL, &o, NULL, NULL);
   1030 		}
   1031 	}
   1032 }
   1033 
   1034 static void
   1035 SetForExit()
   1036 {
   1037 	setconnmode(0);
   1038 	do {
   1039 		(void) telrcv();		/* Process any incoming data */
   1040 		EmptyTerminal();
   1041 	} while (ring_full_count(&netiring));	/* While there is any */
   1042 	setcommandmode();
   1043 	(void) fflush(stdout);
   1044 	(void) fflush(stderr);
   1045 	setconnmode(0);
   1046 	EmptyTerminal();			/* Flush the path to the tty */
   1047 	setcommandmode();
   1048 }
   1049 
   1050 void
   1051 Exit(returnCode)
   1052 	int returnCode;
   1053 {
   1054 	SetForExit();
   1055 	exit(returnCode);
   1056 }
   1057 
   1058 void
   1059 ExitString(string, returnCode)
   1060 	char *string;
   1061 	int returnCode;
   1062 {
   1063 	SetForExit();
   1064 	(void) fwrite(string, 1, strlen(string), stderr);
   1065 	exit(returnCode);
   1066 }
   1067 
   1068 #define	BUFFER_CHUNK_SIZE 64
   1069 
   1070 /* Round up to a multiple of BUFFER_CHUNK_SIZE */
   1071 #define	ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \
   1072 		BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE)
   1073 
   1074 /*
   1075  * Optionally allocate a buffer, and optionally read a string from a stream
   1076  * into the buffer, starting at the given offset.  If the buffer isn't
   1077  * large enough for the given offset, or if buffer space is exhausted
   1078  * when reading the string, the size of the buffer is increased.
   1079  *
   1080  * A buffer can be supplied when the function is called, passing the
   1081  * buffer address via the first argument.  The buffer size can be
   1082  * passed as well, in the second argument.  If the second argument is
   1083  * NULL, the function makes no assumptions about the buffer size.
   1084  * The address of the buffer is returned via the first argument, and the
   1085  * buffer size via the second argument if this is not NULL.
   1086  * These returned values may differ from the supplied values if the buffer
   1087  * was reallocated.
   1088  *
   1089  * If no buffer is to be supplied, specify a buffer address of NULL, via
   1090  * the first argument.
   1091  *
   1092  * If the pointer to the buffer address is NULL, the function just returns
   1093  * NULL, and performs no other processing.
   1094  *
   1095  * If a NULL stream is passed, the function will just make sure the
   1096  * supplied buffer is large enough to hold the supplied offset,
   1097  * reallocating it if is too small or too large.
   1098  *
   1099  * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size.
   1100  *
   1101  * The function stops reading from the stream when a newline is read,
   1102  * end of file is reached, or an error occurs.  The newline is not
   1103  * returned in the buffer.  The returned string will be NULL terminated.
   1104  *
   1105  * The function returns the address of the buffer if any characters
   1106  * are read and no error occurred, otherwise it returns NULL.
   1107  *
   1108  * If the function returns NULL, a buffer may have been allocated.  The
   1109  * buffer address will be returned via the first argument, together with
   1110  * the buffer size if the second argument is not NULL.
   1111  *
   1112  */
   1113 static char *
   1114 GetStringAtOffset(bufp, cbufsiz, off, st)
   1115 	char **bufp;
   1116 	unsigned int *cbufsiz;
   1117 	unsigned int off;
   1118 	FILE *st;
   1119 {
   1120 	unsigned int bufsiz;
   1121 	char *buf;
   1122 	char *nbuf;
   1123 	unsigned int idx = off;
   1124 
   1125 	if (bufp == NULL)
   1126 		return (NULL);
   1127 
   1128 	buf = *bufp;
   1129 
   1130 	bufsiz = ROUND_CHUNK_SIZE(off + 1);
   1131 
   1132 	if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) {
   1133 		if ((nbuf = realloc(buf, bufsiz)) == NULL)
   1134 			return (NULL);
   1135 
   1136 		buf = nbuf;
   1137 		*bufp = buf;
   1138 		if (cbufsiz != NULL)
   1139 			*cbufsiz = bufsiz;
   1140 	}
   1141 
   1142 
   1143 	if (st == NULL)
   1144 		return (buf);
   1145 
   1146 	clearerr(st);
   1147 	for (;;) {
   1148 		int c = getc(st);
   1149 
   1150 		/* Expand the buffer as needed. */
   1151 		if (idx == bufsiz) {
   1152 			bufsiz += BUFFER_CHUNK_SIZE;
   1153 			if ((nbuf = realloc(buf, bufsiz)) == NULL) {
   1154 				/* Discard everything we read. */
   1155 				buf[off] = 0;
   1156 				buf = NULL;
   1157 				break;
   1158 			}
   1159 			buf = nbuf;
   1160 			*bufp = buf;
   1161 			if (cbufsiz != NULL)
   1162 				*cbufsiz = bufsiz;
   1163 		}
   1164 
   1165 		if (c == EOF || c == '\n') {
   1166 			buf[idx] = 0;
   1167 			if (ferror(st) != 0) {
   1168 				/* Retry if interrupted by a signal. */
   1169 				if (errno == EINTR) {
   1170 					clearerr(st);
   1171 					continue;
   1172 				}
   1173 				buf = NULL;
   1174 			} else if (