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
upcase(argument)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
SetSockOpt(fd,level,option,yesno)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
SetNetTrace(file)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
Dump(direction,buffer,length)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
printoption(direction,cmd,option)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
optionstatus()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
printsub(direction,pointer,length)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
EmptyTerminal()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
SetForExit()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
Exit(returnCode)1051 Exit(returnCode)
1052 int returnCode;
1053 {
1054 SetForExit();
1055 exit(returnCode);
1056 }
1057
1058 void
ExitString(string,returnCode)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 *
GetStringAtOffset(bufp,cbufsiz,off,st)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 (feof(st) != 0) {
1175 /* No characters transferred? */
1176 if (off == idx)
1177 buf = NULL;
1178 }
1179 break;
1180 }
1181 buf[idx++] = c;
1182 }
1183 return (buf);
1184 }
1185
1186 /*
1187 * Read a string from the supplied stream. Stop reading when a newline
1188 * is read, end of file reached, or an error occurs.
1189 *
1190 * A buffer can be supplied by specifying the buffer address via the
1191 * first argument. The buffer size can be passed via the second argument.
1192 * If the second argument is NULL, the function makes no assumptions
1193 * about the buffer size. The buffer will be reallocated if it is too
1194 * small or too large for the returned string.
1195 *
1196 * If no buffer is to be supplied, specify a buffer address of NULL,
1197 * via the first argument.
1198 *
1199 * If the first argument is NULL, the function just returns NULL, and
1200 * performs no other processing.
1201 *
1202 * The function returns the address of the buffer if any characters are
1203 * read and no error occurred.
1204 *
1205 * If the function returns NULL, a buffer may have been allocated. The
1206 * buffer address and buffer size will be returned via the first argument,
1207 * and the buffer size via the second argument, if this isn't NULL.
1208 */
1209 char *
GetString(bufp,bufsiz,st)1210 GetString(bufp, bufsiz, st)
1211 char **bufp;
1212 unsigned int *bufsiz;
1213 FILE *st;
1214 {
1215 return (GetStringAtOffset(bufp, bufsiz, 0, st));
1216 }
1217
1218 /*
1219 * Allocate a buffer to hold a string of given length.
1220 *
1221 * An existing buffer can be reallocated by passing its address and via
1222 * the first argument. The buffer size can be passed via the second
1223 * argument. If the second argument is NULL, the function makes no
1224 * assumptions about the buffer size.
1225 *
1226 * If no existing buffer is to be supplied, pass a NULL buffer address via
1227 * the first argument.
1228 *
1229 * If the first argument is NULL, the function just returns NULL,
1230 * and performs no other processing.
1231 */
1232 char *
AllocStringBuffer(bufp,bufsiz,size)1233 AllocStringBuffer(bufp, bufsiz, size)
1234 char **bufp;
1235 unsigned int *bufsiz;
1236 unsigned int size;
1237 {
1238 return (GetStringAtOffset(bufp, bufsiz, size, (FILE *)NULL));
1239 }
1240
1241 /*
1242 * This function is similar to GetString(), except that the string read
1243 * from the stream is appended to the supplied string.
1244 */
1245 char *
GetAndAppendString(bufp,bufsiz,str,st)1246 GetAndAppendString(bufp, bufsiz, str, st)
1247 char **bufp;
1248 unsigned int *bufsiz;
1249 char *str;
1250 FILE *st;
1251 {
1252 unsigned int off = strlen(str);
1253
1254 if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL)
1255 return (NULL);
1256
1257 return (memcpy(*bufp, str, off));
1258 }
1259