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