Sync usage with man page.
[netbsd-mini2440.git] / libexec / telnetd / utility.c
blobfc2ec871bc439c28413294ea27f6d9443ffd949d
1 /* $NetBSD: utility.c,v 1.30 2006/10/07 18:26:40 elad Exp $ */
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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.30 2006/10/07 18:26:40 elad Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/utsname.h>
42 #include <ctype.h>
43 #define PRINTOPTIONS
44 #include "telnetd.h"
46 char *nextitem(char *);
47 void putstr(char *);
49 extern int not42;
52 * utility functions performing io related tasks
56 * ttloop
58 * A small subroutine to flush the network output buffer, get some data
59 * from the network, and pass it through the telnet state machine. We
60 * also flush the pty input buffer (by dropping its data) if it becomes
61 * too full.
64 void
65 ttloop(void)
68 DIAG(TD_REPORT, {output_data("td: ttloop\r\n");});
69 if (nfrontp - nbackp) {
70 netflush();
72 ncc = read(net, netibuf, sizeof netibuf);
73 if (ncc < 0) {
74 syslog(LOG_ERR, "ttloop: read: %m");
75 exit(1);
76 } else if (ncc == 0) {
77 syslog(LOG_INFO, "ttloop: unexpected EOF from peer");
78 exit(1);
80 DIAG(TD_REPORT, {output_data("td: ttloop read %d chars\r\n", ncc);});
81 netip = netibuf;
82 telrcv(); /* state machine */
83 if (ncc > 0) {
84 pfrontp = pbackp = ptyobuf;
85 telrcv();
87 } /* end of ttloop */
90 * Check a descriptor to see if out of band data exists on it.
92 int
93 stilloob(int s /* socket number */)
95 struct pollfd set[1];
96 int value;
98 set[0].fd = s;
99 set[0].events = POLLPRI;
100 do {
101 value = poll(set, 1, 0);
102 } while ((value == -1) && (errno == EINTR));
104 if (value < 0) {
105 fatalperror(pty, "poll");
107 if (set[0].revents & POLLPRI) {
108 return 1;
109 } else {
110 return 0;
114 void
115 ptyflush(void)
117 int n;
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);
125 if (n < 0) {
126 if (errno == EWOULDBLOCK || errno == EINTR)
127 return;
128 cleanup(0);
130 pbackp += n;
131 if (pbackp == pfrontp)
132 pbackp = pfrontp = ptyobuf;
136 * nextitem()
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.
145 char *
146 nextitem(char *current)
148 if ((*current&0xff) != IAC) {
149 return current+1;
151 switch (*(current+1)&0xff) {
152 case DO:
153 case DONT:
154 case WILL:
155 case WONT:
156 return current+3;
157 case SB: /* loop forever looking for the SE */
159 char *look = current+2;
161 for (;;) {
162 if ((*look++&0xff) == IAC) {
163 if ((*look++&0xff) == SE) {
164 return look;
169 default:
170 return current+2;
172 } /* end of nextitem */
176 * netclear()
178 * We are about to do a TELNET SYNCH operation. Clear
179 * the path to the network.
181 * Things are a bit tricky since we may have sent the first
182 * byte or so of a previous TELNET command into the network.
183 * So, we have to scan the network buffer from the beginning
184 * until we are up to where we want to be.
186 * A side effect of what we do, just to keep things
187 * simple, is to clear the urgent data pointer. The principal
188 * caller should be setting the urgent data pointer AFTER calling
189 * us in any case.
191 void
192 netclear(void)
194 char *thisitem, *next;
195 char *good;
196 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
197 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
199 #ifdef ENCRYPTION
200 thisitem = nclearto > netobuf ? nclearto : netobuf;
201 #else /* ENCRYPTION */
202 thisitem = netobuf;
203 #endif /* ENCRYPTION */
205 while ((next = nextitem(thisitem)) <= nbackp) {
206 thisitem = next;
209 /* Now, thisitem is first before/at boundary. */
211 #ifdef ENCRYPTION
212 good = nclearto > netobuf ? nclearto : netobuf;
213 #else /* ENCRYPTION */
214 good = netobuf; /* where the good bytes go */
215 #endif /* ENCRYPTION */
217 while (nfrontp > thisitem) {
218 if (wewant(thisitem)) {
219 int length;
221 next = thisitem;
222 do {
223 next = nextitem(next);
224 } while (wewant(next) && (nfrontp > next));
225 length = next-thisitem;
226 memmove(good, thisitem, length);
227 good += length;
228 thisitem = next;
229 } else {
230 thisitem = nextitem(thisitem);
234 nbackp = netobuf;
235 nfrontp = good; /* next byte to be sent */
236 neturg = 0;
237 } /* end of netclear */
240 * netflush
241 * Send as much data as possible to the network,
242 * handling requests for urgent data.
244 void
245 netflush(void)
247 int n;
249 if ((n = nfrontp - nbackp) > 0) {
250 DIAG(TD_REPORT,
251 { output_data("td: netflush %d chars\r\n", n);
252 n = nfrontp - nbackp; /* re-compute count */
254 #ifdef ENCRYPTION
255 if (encrypt_output) {
256 char *s = nclearto ? nclearto : nbackp;
257 if (nfrontp - s > 0) {
258 (*encrypt_output)((unsigned char *)s, nfrontp - s);
259 nclearto = nfrontp;
262 #endif /* ENCRYPTION */
264 * if no urgent data, or if the other side appears to be an
265 * old 4.2 client (and thus unable to survive TCP urgent data),
266 * write the entire buffer in non-OOB mode.
268 if ((neturg == 0) || (not42 == 0)) {
269 n = write(net, nbackp, n); /* normal write */
270 } else {
271 n = neturg - nbackp;
273 * In 4.2 (and 4.3) systems, there is some question about
274 * what byte in a sendOOB operation is the "OOB" data.
275 * To make ourselves compatible, we only send ONE byte
276 * out of band, the one WE THINK should be OOB (though
277 * we really have more the TCP philosophy of urgent data
278 * rather than the Unix philosophy of OOB data).
280 if (n > 1) {
281 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
282 } else {
283 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
287 if (n < 0) {
288 if (errno == EWOULDBLOCK || errno == EINTR)
289 return;
290 cleanup(0);
292 nbackp += n;
293 #ifdef ENCRYPTION
294 if (nbackp > nclearto)
295 nclearto = 0;
296 #endif /* ENCRYPTION */
297 if (nbackp >= neturg) {
298 neturg = 0;
300 if (nbackp == nfrontp) {
301 nbackp = nfrontp = netobuf;
302 #ifdef ENCRYPTION
303 nclearto = 0;
304 #endif /* ENCRYPTION */
306 return;
307 } /* end of netflush */
311 * writenet
313 * Just a handy little function to write a bit of raw data to the net.
314 * It will force a transmit of the buffer if necessary
316 * arguments
317 * ptr - A pointer to a character string to write
318 * len - How many bytes to write
320 void
321 writenet(unsigned char *ptr, int len)
323 /* flush buffer if no room for new data) */
324 if ((&netobuf[BUFSIZ] - nfrontp) < len) {
325 /* if this fails, don't worry, buffer is a little big */
326 netflush();
329 memmove(nfrontp, ptr, len);
330 nfrontp += len;
332 } /* end of writenet */
336 * miscellaneous functions doing a variety of little jobs follow ...
338 void
339 fatal(int f, const char *msg)
341 char buf[BUFSIZ];
343 (void)snprintf(buf, sizeof buf, "telnetd: %s.\r\n", msg);
344 #ifdef ENCRYPTION
345 if (encrypt_output) {
347 * Better turn off encryption first....
348 * Hope it flushes...
350 encrypt_send_end();
351 netflush();
353 #endif /* ENCRYPTION */
354 (void)write(f, buf, (int)strlen(buf));
355 sleep(1); /*XXX*/
356 exit(1);
359 void
360 fatalperror(f, msg)
361 int f;
362 const char *msg;
364 char buf[BUFSIZ];
366 (void)snprintf(buf, sizeof buf, "%s: %s", msg, strerror(errno));
367 fatal(f, buf);
370 char editedhost[MAXHOSTNAMELEN];
372 void
373 edithost(char *pat, char *host)
375 char *res = editedhost;
377 if (!pat)
378 pat = "";
379 while (*pat) {
380 switch (*pat) {
382 case '#':
383 if (*host)
384 host++;
385 break;
387 case '@':
388 if (*host)
389 *res++ = *host++;
390 break;
392 default:
393 *res++ = *pat;
394 break;
396 if (res == &editedhost[sizeof editedhost - 1]) {
397 *res = '\0';
398 return;
400 pat++;
402 if (*host)
403 (void) strncpy(res, host,
404 sizeof editedhost - (res - editedhost) -1);
405 else
406 *res = '\0';
407 editedhost[sizeof editedhost - 1] = '\0';
410 static char *putlocation;
412 void
413 putstr(char *s)
416 while (*s)
417 putchr(*s++);
420 void
421 putchr(int cc)
423 *putlocation++ = cc;
427 * This is split on two lines so that SCCS will not see the M
428 * between two % signs and expand it...
430 static char fmtstr[] = { "%l:%M\
431 %p on %A, %d %B %Y" };
433 char *
434 putf(char *cp, char *where)
436 char *slash;
437 time_t t;
438 char db[100];
439 struct utsname utsinfo;
441 uname(&utsinfo);
443 putlocation = where;
445 while (*cp) {
446 if (*cp != '%') {
447 putchr(*cp++);
448 continue;
450 switch (*++cp) {
452 case 't':
453 if ((slash = strstr(line, "/pts/")) == NULL)
454 slash = strrchr(line, '/');
455 if (slash == (char *) 0)
456 putstr(line);
457 else
458 putstr(&slash[1]);
459 break;
461 case 'h':
462 putstr(editedhost);
463 break;
465 case 'd':
466 (void)time(&t);
467 (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
468 putstr(db);
469 break;
471 case '%':
472 putchr('%');
473 break;
475 case 's':
476 putstr(utsinfo.sysname);
477 break;
479 case 'm':
480 putstr(utsinfo.machine);
481 break;
483 case 'r':
484 putstr(utsinfo.release);
485 break;
487 case 'v':
488 putstr(utsinfo.version);
489 break;
491 cp++;
494 return (putlocation);
497 #ifdef DIAGNOSTICS
499 * Print telnet options and commands in plain text, if possible.
501 void
502 printoption(const char *fmt, int option)
504 if (TELOPT_OK(option))
505 output_data("%s %s\r\n", fmt, TELOPT(option));
506 else if (TELCMD_OK(option))
507 output_data("%s %s\r\n", fmt, TELCMD(option));
508 else
509 output_data("%s %d\r\n", fmt, option);
510 return;
513 void
514 printsub(
515 int direction, /* '<' or '>' */
516 unsigned char *pointer, /* where suboption data sits */
517 int length) /* length of suboption data */
519 int i = 0;
520 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
521 u_char buf[512];
522 #endif
524 if (!(diagnostic & TD_OPTIONS))
525 return;
527 if (direction) {
528 output_data("td: %s suboption ",
529 direction == '<' ? "recv" : "send");
530 if (length >= 3) {
531 int j;
533 i = pointer[length - 2];
534 j = pointer[length - 1];
536 if (i != IAC || j != SE) {
537 output_data("(terminated by ");
538 if (TELOPT_OK(i))
539 output_data("%s ", TELOPT(i));
540 else if (TELCMD_OK(i))
541 output_data("%s ", TELCMD(i));
542 else
543 output_data("%d ", i);
544 if (TELOPT_OK(j))
545 output_data("%s", TELOPT(j));
546 else if (TELCMD_OK(j))
547 output_data("%s", TELCMD(j));
548 else
549 output_data("%d", j);
550 output_data(", not IAC SE!) ");
553 length -= 2;
555 if (length < 1) {
556 output_data("(Empty suboption??\?)");
557 return;
559 switch (pointer[0]) {
560 case TELOPT_TTYPE:
561 output_data("TERMINAL-TYPE ");
562 switch (pointer[1]) {
563 case TELQUAL_IS:
564 output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
565 break;
566 case TELQUAL_SEND:
567 output_data("SEND");
568 break;
569 default:
570 output_data("- unknown qualifier %d (0x%x).",
571 pointer[1], pointer[1]);
573 break;
574 case TELOPT_TSPEED:
575 output_data("TERMINAL-SPEED");
576 if (length < 2) {
577 output_data(" (empty suboption??\?)");
578 break;
580 switch (pointer[1]) {
581 case TELQUAL_IS:
582 output_data(" IS %.*s", length-2, (char *)pointer+2);
583 break;
584 default:
585 if (pointer[1] == 1)
586 output_data(" SEND");
587 else
588 output_data(" %d (unknown)", pointer[1]);
589 for (i = 2; i < length; i++) {
590 output_data(" ?%d?", pointer[i]);
592 break;
594 break;
596 case TELOPT_LFLOW:
597 output_data("TOGGLE-FLOW-CONTROL");
598 if (length < 2) {
599 output_data(" (empty suboption??\?)");
600 break;
602 switch (pointer[1]) {
603 case LFLOW_OFF:
604 output_data(" OFF"); break;
605 case LFLOW_ON:
606 output_data(" ON"); break;
607 case LFLOW_RESTART_ANY:
608 output_data(" RESTART-ANY"); break;
609 case LFLOW_RESTART_XON:
610 output_data(" RESTART-XON"); break;
611 default:
612 output_data(" %d (unknown)", pointer[1]);
614 for (i = 2; i < length; i++)
615 output_data(" ?%d?", pointer[i]);
616 break;
618 case TELOPT_NAWS:
619 output_data("NAWS");
620 if (length < 2) {
621 output_data(" (empty suboption??\?)");
622 break;
624 if (length == 2) {
625 output_data(" ?%d?", pointer[1]);
626 break;
628 output_data(" %d %d (%d)",
629 pointer[1], pointer[2],
630 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
631 if (length == 4) {
632 output_data(" ?%d?", pointer[3]);
633 break;
635 output_data(" %d %d (%d)", pointer[3], pointer[4],
636 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
637 for (i = 5; i < length; i++) {
638 output_data(" ?%d?", pointer[i]);
640 break;
642 case TELOPT_LINEMODE:
643 output_data("LINEMODE ");
644 if (length < 2) {
645 output_data(" (empty suboption??\?)");
646 break;
648 switch (pointer[1]) {
649 case WILL:
650 output_data("WILL ");
651 goto common;
652 case WONT:
653 output_data("WONT ");
654 goto common;
655 case DO:
656 output_data("DO ");
657 goto common;
658 case DONT:
659 output_data("DONT ");
660 common:
661 if (length < 3) {
662 output_data("(no option??\?)");
663 break;
665 switch (pointer[2]) {
666 case LM_FORWARDMASK:
667 output_data("Forward Mask");
668 for (i = 3; i < length; i++)
669 output_data(" %x", pointer[i]);
670 break;
671 default:
672 output_data("%d (unknown)", pointer[2]);
673 for (i = 3; i < length; i++)
674 output_data(" %d", pointer[i]);
675 break;
677 break;
679 case LM_SLC:
680 output_data("SLC");
681 for (i = 2; i < length - 2; i += 3) {
682 if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
683 output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
684 else
685 output_data(" %d", pointer[i+SLC_FUNC]);
686 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
687 case SLC_NOSUPPORT:
688 output_data(" NOSUPPORT"); break;
689 case SLC_CANTCHANGE:
690 output_data(" CANTCHANGE"); break;
691 case SLC_VARIABLE:
692 output_data(" VARIABLE"); break;
693 case SLC_DEFAULT:
694 output_data(" DEFAULT"); break;
696 output_data("%s%s%s",
697 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
698 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
699 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
700 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
701 SLC_FLUSHOUT| SLC_LEVELBITS)) {
702 output_data("(0x%x)", pointer[i+SLC_FLAGS]);
704 output_data(" %d;", pointer[i+SLC_VALUE]);
705 if ((pointer[i+SLC_VALUE] == IAC) &&
706 (pointer[i+SLC_VALUE+1] == IAC))
707 i++;
709 for (; i < length; i++)
710 output_data(" ?%d?", pointer[i]);
711 break;
713 case LM_MODE:
714 output_data("MODE ");
715 if (length < 3) {
716 output_data("(no mode??\?)");
717 break;
720 char tbuf[32];
722 (void)snprintf(tbuf, sizeof tbuf, "%s%s%s%s%s",
723 pointer[2]&MODE_EDIT ? "|EDIT" : "",
724 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
725 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
726 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
727 pointer[2]&MODE_ACK ? "|ACK" : "");
728 output_data("%s", tbuf[1] ? &tbuf[1] : "0");
730 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
731 output_data(" (0x%x)", pointer[2]);
732 for (i = 3; i < length; i++)
733 output_data(" ?0x%x?", pointer[i]);
734 break;
735 default:
736 output_data("%d (unknown)", pointer[1]);
737 for (i = 2; i < length; i++)
738 output_data(" %d", pointer[i]);
740 break;
742 case TELOPT_STATUS: {
743 char *cp;
744 int j, k;
746 output_data("STATUS");
748 switch (pointer[1]) {
749 default:
750 if (pointer[1] == TELQUAL_SEND)
751 output_data(" SEND");
752 else
753 output_data(" %d (unknown)", pointer[1]);
754 for (i = 2; i < length; i++)
755 output_data(" ?%d?", pointer[i]);
756 break;
757 case TELQUAL_IS:
758 output_data(" IS\r\n");
760 for (i = 2; i < length; i++) {
761 switch(pointer[i]) {
762 case DO: cp = "DO"; goto common2;
763 case DONT: cp = "DONT"; goto common2;
764 case WILL: cp = "WILL"; goto common2;
765 case WONT: cp = "WONT"; goto common2;
766 common2:
767 i++;
768 if (TELOPT_OK(pointer[i]))
769 output_data(" %s %s", cp, TELOPT(pointer[i]));
770 else
771 output_data(" %s %d", cp, pointer[i]);
773 output_data("\r\n");
774 break;
776 case SB:
777 output_data(" SB ");
778 i++;
779 j = k = i;
780 while (j < length) {
781 if (pointer[j] == SE) {
782 if (j+1 == length)
783 break;
784 if (pointer[j+1] == SE)
785 j++;
786 else
787 break;
789 pointer[k++] = pointer[j++];
791 printsub(0, &pointer[i], k - i);
792 if (i < length) {
793 output_data(" SE");
794 i = j;
795 } else
796 i = j - 1;
798 output_data("\r\n");
800 break;
802 default:
803 output_data(" %d", pointer[i]);
804 break;
807 break;
809 break;
812 case TELOPT_XDISPLOC:
813 output_data("X-DISPLAY-LOCATION ");
814 switch (pointer[1]) {
815 case TELQUAL_IS:
816 output_data("IS \"%.*s\"", length - 2, (char *)pointer + 2);
817 break;
818 case TELQUAL_SEND:
819 output_data("SEND");
820 break;
821 default:
822 output_data("- unknown qualifier %d (0x%x).",
823 pointer[1], pointer[1]);
825 break;
827 case TELOPT_NEW_ENVIRON:
828 output_data("NEW-ENVIRON ");
829 goto env_common1;
830 case TELOPT_OLD_ENVIRON:
831 output_data("OLD-ENVIRON");
832 env_common1:
833 switch (pointer[1]) {
834 case TELQUAL_IS:
835 output_data("IS ");
836 goto env_common;
837 case TELQUAL_SEND:
838 output_data("SEND ");
839 goto env_common;
840 case TELQUAL_INFO:
841 output_data("INFO ");
842 env_common:
844 int noquote = 2;
845 for (i = 2; i < length; i++ ) {
846 switch (pointer[i]) {
847 case NEW_ENV_VAR:
848 output_data("%s", "\" VAR " + noquote);
849 noquote = 2;
850 break;
852 case NEW_ENV_VALUE:
853 output_data("%s", "\" VALUE " + noquote);
854 noquote = 2;
855 break;
857 case ENV_ESC:
858 output_data("%s", "\" ESC " + noquote);
859 noquote = 2;
860 break;
862 case ENV_USERVAR:
863 output_data("%s", "\" USERVAR " + noquote);
864 noquote = 2;
865 break;
867 default:
868 if (isprint(pointer[i]) && pointer[i] != '"') {
869 if (noquote) {
870 output_data("\"");
871 noquote = 0;
873 output_data("%c", pointer[i]);
874 } else {
875 output_data("\" %03o " + noquote, pointer[i]);
876 noquote = 2;
878 break;
881 if (!noquote)
882 output_data("\"");
883 break;
886 break;
888 #ifdef AUTHENTICATION
889 case TELOPT_AUTHENTICATION:
890 output_data("AUTHENTICATION");
892 if (length < 2) {
893 output_data(" (empty suboption??\?)");
894 break;
896 switch (pointer[1]) {
897 case TELQUAL_REPLY:
898 case TELQUAL_IS:
899 output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
900 "IS" : "REPLY");
901 if (AUTHTYPE_NAME_OK(pointer[2]))
902 output_data("%s ", AUTHTYPE_NAME(pointer[2]));
903 else
904 output_data("%d ", pointer[2]);
905 if (length < 3) {
906 output_data("(partial suboption??\?)");
907 break;
909 output_data("%s|%s",
910 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
911 "CLIENT" : "SERVER",
912 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
913 "MUTUAL" : "ONE-WAY");
915 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
916 output_data("%s", buf);
917 break;
919 case TELQUAL_SEND:
920 i = 2;
921 output_data(" SEND ");
922 while (i < length) {
923 if (AUTHTYPE_NAME_OK(pointer[i]))
924 output_data("%s ", AUTHTYPE_NAME(pointer[i]));
925 else
926 output_data("%d ", pointer[i]);
927 if (++i >= length) {
928 output_data("(partial suboption??\?)");
929 break;
931 output_data("%s|%s ",
932 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
933 "CLIENT" : "SERVER",
934 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
935 "MUTUAL" : "ONE-WAY");
936 ++i;
938 break;
940 case TELQUAL_NAME:
941 i = 2;
942 output_data(" NAME \"");
943 while (i < length) {
944 if (isprint(pointer[i]))
945 output_data("%c", pointer[i++]);
946 else
947 output_data("\"%03o\"",pointer[i++]);
949 output_data("\"");
950 break;
952 default:
953 for (i = 2; i < length; i++)
954 output_data(" ?%d?", pointer[i]);
955 break;
957 break;
958 #endif
960 #ifdef ENCRYPTION
961 case TELOPT_ENCRYPT:
962 output_data("ENCRYPT");
963 if (length < 2) {
964 output_data(" (empty suboption??\?)");
965 break;
967 switch (pointer[1]) {
968 case ENCRYPT_START:
969 output_data(" START");
970 break;
972 case ENCRYPT_END:
973 output_data(" END");
974 break;
976 case ENCRYPT_REQSTART:
977 output_data(" REQUEST-START");
978 break;
980 case ENCRYPT_REQEND:
981 output_data(" REQUEST-END");
982 break;
984 case ENCRYPT_IS:
985 case ENCRYPT_REPLY:
986 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
987 "IS" : "REPLY");
988 if (length < 3) {
989 output_data(" (partial suboption??\?)");
990 break;
992 if (ENCTYPE_NAME_OK(pointer[2]))
993 output_data("%s ", ENCTYPE_NAME(pointer[2]));
994 else
995 output_data(" %d (unknown)", pointer[2]);
997 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
998 output_data("%s", buf);
999 break;
1001 case ENCRYPT_SUPPORT:
1002 i = 2;
1003 output_data(" SUPPORT ");
1004 while (i < length) {
1005 if (ENCTYPE_NAME_OK(pointer[i]))
1006 output_data("%s ", ENCTYPE_NAME(pointer[i]));
1007 else
1008 output_data("%d ", pointer[i]);
1009 i++;
1011 break;
1013 case ENCRYPT_ENC_KEYID:
1014 output_data(" ENC_KEYID");
1015 goto encommon;
1017 case ENCRYPT_DEC_KEYID:
1018 output_data(" DEC_KEYID");
1019 goto encommon;
1021 default:
1022 output_data(" %d (unknown)", pointer[1]);
1023 encommon:
1024 for (i = 2; i < length; i++)
1025 output_data(" %d", pointer[i]);
1026 break;
1028 break;
1029 #endif /* ENCRYPTION */
1031 default:
1032 if (TELOPT_OK(pointer[0]))
1033 output_data("%s (unknown)", TELOPT(pointer[0]));
1034 else
1035 output_data("%d (unknown)", pointer[i]);
1036 for (i = 1; i < length; i++)
1037 output_data(" %d", pointer[i]);
1038 break;
1040 output_data("\r\n");
1044 * Dump a data buffer in hex and ascii to the output data stream.
1046 void
1047 printdata(char *tag, char *ptr, int cnt)
1049 int i;
1050 char xbuf[30];
1052 while (cnt) {
1053 /* flush net output buffer if no room for new data) */
1054 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
1055 netflush();
1058 /* add a line of output */
1059 output_data("%s: ", tag);
1060 for (i = 0; i < 20 && cnt; i++) {
1061 output_data("%02x", *ptr);
1062 if (isprint((unsigned char)*ptr)) {
1063 xbuf[i] = *ptr;
1064 } else {
1065 xbuf[i] = '.';
1067 if (i % 2)
1068 output_data(" ");
1069 cnt--;
1070 ptr++;
1072 xbuf[i] = '\0';
1073 output_data(" %s\r\n", xbuf);
1076 #endif /* DIAGNOSTICS */