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