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