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