1 /* $NetBSD: utility.c,v 1.32 2012/01/09 16:36:48 christos 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.32 2012/01/09 16:36:48 christos Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include <sys/utsname.h>
42 #include <ctype.h>
43 #define PRINTOPTIONS
44 #include "telnetd.h"
45
46 char *nextitem(char *);
47 void putstr(char *);
48
49 extern int not42;
50
51 /*
52 * utility functions performing io related tasks
53 */
54
55 /*
56 * ttloop
57 *
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.
62 */
63
64 void
ttloop(void)65 ttloop(void)
66 {
67
68 DIAG(TD_REPORT, {output_data("td: ttloop\r\n");});
69 if (nfrontp - nbackp) {
70 netflush();
71 }
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);
79 }
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();
86 }
87 } /* end of ttloop */
88
89 /*
90 * Check a descriptor to see if out of band data exists on it.
91 */
92 int
stilloob(int s)93 stilloob(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
ptyflush(void)115 ptyflush(void)
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 *
nextitem(char * current)146 nextitem(char *current)
147 {
148 if ((*current&0xff) != IAC) {
149 return current+1;
150 }
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 */
158 {
159 char *look = current+2;
160
161 for (;;) {
162 if ((*look++&0xff) == IAC) {
163 if ((*look++&0xff) == SE) {
164 return look;
165 }
166 }
167 }
168 }
169 default:
170 return current+2;
171 }
172 } /* end of nextitem */
173
174
175 /*
176 * netclear()
177 *
178 * We are about to do a TELNET SYNCH operation. Clear
179 * the path to the network.
180 *
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.
185 *
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.
190 */
191 void
netclear(void)192 netclear(void)
193 {
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))
198
199 #ifdef ENCRYPTION
200 thisitem = nclearto > netobuf ? nclearto : netobuf;
201 #else /* ENCRYPTION */
202 thisitem = netobuf;
203 #endif /* ENCRYPTION */
204
205 while ((next = nextitem(thisitem)) <= nbackp) {
206 thisitem = next;
207 }
208
209 /* Now, thisitem is first before/at boundary. */
210
211 #ifdef ENCRYPTION
212 good = nclearto > netobuf ? nclearto : netobuf;
213 #else /* ENCRYPTION */
214 good = netobuf; /* where the good bytes go */
215 #endif /* ENCRYPTION */
216
217 while (nfrontp > thisitem) {
218 if (wewant(thisitem)) {
219 int length;
220
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);
231 }
232 }
233
234 nbackp = netobuf;
235 nfrontp = good; /* next byte to be sent */
236 neturg = 0;
237 } /* end of netclear */
238
239 /*
240 * netflush
241 * Send as much data as possible to the network,
242 * handling requests for urgent data.
243 */
244 void
netflush(void)245 netflush(void)
246 {
247 int n;
248
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 */
253 });
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;
260 }
261 }
262 #endif /* ENCRYPTION */
263 /*
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.
267 */
268 if ((neturg == 0) || (not42 == 0)) {
269 n = write(net, nbackp, n); /* normal write */
270 } else {
271 n = neturg - nbackp;
272 /*
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).
279 */
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 */
284 }
285 }
286 }
287 if (n < 0) {
288 if (errno == EWOULDBLOCK || errno == EINTR)
289 return;
290 cleanup(0);
291 }
292 nbackp += n;
293 #ifdef ENCRYPTION
294 if (nbackp > nclearto)
295 nclearto = 0;
296 #endif /* ENCRYPTION */
297 if (nbackp >= neturg) {
298 neturg = 0;
299 }
300 if (nbackp == nfrontp) {
301 nbackp = nfrontp = netobuf;
302 #ifdef ENCRYPTION
303 nclearto = 0;
304 #endif /* ENCRYPTION */
305 }
306 return;
307 } /* end of netflush */
308
309
310 /*
311 * writenet
312 *
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
315 *
316 * arguments
317 * ptr - A pointer to a character string to write
318 * len - How many bytes to write
319 */
320 void
writenet(unsigned char * ptr,int len)321 writenet(unsigned char *ptr, int len)
322 {
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();
327 }
328
329 memmove(nfrontp, ptr, len);
330 nfrontp += len;
331
332 } /* end of writenet */
333
334
335 /*
336 * miscellaneous functions doing a variety of little jobs follow ...
337 */
338 void
fatal(int f,const char * msg)339 fatal(int f, const char *msg)
340 {
341 char buf[BUFSIZ];
342
343 (void)snprintf(buf, sizeof buf, "telnetd: %s.\r\n", msg);
344 #ifdef ENCRYPTION
345 if (encrypt_output) {
346 /*
347 * Better turn off encryption first....
348 * Hope it flushes...
349 */
350 encrypt_send_end();
351 netflush();
352 }
353 #endif /* ENCRYPTION */
354 (void)write(f, buf, (int)strlen(buf));
355 sleep(1); /*XXX*/
356 exit(1);
357 }
358
359 void
fatalperror(f,msg)360 fatalperror(f, msg)
361 int f;
362 const char *msg;
363 {
364 char buf[BUFSIZ];
365
366 (void)snprintf(buf, sizeof buf, "%s: %s", msg, strerror(errno));
367 fatal(f, buf);
368 }
369
370 char editedhost[MAXHOSTNAMELEN];
371
372 void
edithost(const char * pat,const char * host)373 edithost(const char *pat, const char *host)
374 {
375 char *res = editedhost;
376
377 if (!pat)
378 pat = "";
379 while (*pat) {
380 switch (*pat) {
381
382 case '#':
383 if (*host)
384 host++;
385 break;
386
387 case '@':
388 if (*host)
389 *res++ = *host++;
390 break;
391
392 default:
393 *res++ = *pat;
394 break;
395 }
396 if (res == &editedhost[sizeof editedhost - 1]) {
397 *res = '\0';
398 return;
399 }
400 pat++;
401 }
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';
408 }
409
410 static char *putlocation;
411
412 void
putstr(char * s)413 putstr(char *s)
414 {
415
416 while (*s)
417 putchr(*s++);
418 }
419
420 void
putchr(int cc)421 putchr(int cc)
422 {
423 *putlocation++ = cc;
424 }
425
426 /*
427 * This is split on two lines so that SCCS will not see the M
428 * between two % signs and expand it...
429 */
430 static const char fmtstr[] = { "%l:%M\
431 %p on %A, %d %B %Y" };
432
433 char *
putf(const char * cp,char * where)434 putf(const char *cp, char *where)
435 {
436 char *slash;
437 time_t t;
438 char db[100];
439 struct utsname utsinfo;
440
441 uname(&utsinfo);
442
443 putlocation = where;
444
445 while (*cp) {
446 if (*cp != '%') {
447 putchr(*cp++);
448 continue;
449 }
450 switch (*++cp) {
451
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;
460
461 case 'h':
462 putstr(editedhost);
463 break;
464
465 case 'd':
466 (void)time(&t);
467 (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
468 putstr(db);
469 break;
470
471 case '%':
472 putchr('%');
473 break;
474
475 case 's':
476 putstr(utsinfo.sysname);
477 break;
478
479 case 'm':
480 putstr(utsinfo.machine);
481 break;
482
483 case 'r':
484 putstr(utsinfo.release);
485 break;
486
487 case 'v':
488 putstr(utsinfo.version);
489 break;
490 }
491 cp++;
492 }
493
494 return (putlocation);
495 }
496
497 #ifdef DIAGNOSTICS
498 /*
499 * Print telnet options and commands in plain text, if possible.
500 */
501 void
printoption(const char * fmt,int option)502 printoption(const char *fmt, int option)
503 {
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;
511 }
512
513 void
printsub(int direction,unsigned char * pointer,int length)514 printsub(
515 int direction, /* '<' or '>' */
516 unsigned char *pointer, /* where suboption data sits */
517 int length) /* length of suboption data */
518 {
519 int i = 0;
520 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
521 u_char buf[512];
522 #endif
523
524 if (!(diagnostic & TD_OPTIONS))
525 return;
526
527 if (direction) {
528 output_data("td: %s suboption ",
529 direction == '<' ? "recv" : "send");
530 if (length >= 3) {
531 int j;
532
533 i = pointer[length - 2];
534 j = pointer[length - 1];
535
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!) ");
551 }
552 }
553 length -= 2;
554 }
555 if (length < 1) {
556 output_data("(Empty suboption??\?)");
557 return;
558 }
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]);
572 }
573 break;
574 case TELOPT_TSPEED:
575 output_data("TERMINAL-SPEED");
576 if (length < 2) {
577 output_data(" (empty suboption??\?)");
578 break;
579 }
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]);
591 }
592 break;
593 }
594 break;
595
596 case TELOPT_LFLOW:
597 output_data("TOGGLE-FLOW-CONTROL");
598 if (length < 2) {
599 output_data(" (empty suboption??\?)");
600 break;
601 }
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]);
613 }
614 for (i = 2; i < length; i++)
615 output_data(" ?%d?", pointer[i]);
616 break;
617
618 case TELOPT_NAWS:
619 output_data("NAWS");
620 if (length < 2) {
621 output_data(" (empty suboption??\?)");
622 break;
623 }
624 if (length == 2) {
625 output_data(" ?%d?", pointer[1]);
626 break;
627 }
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;
634 }
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]);
639 }
640 break;
641
642 case TELOPT_LINEMODE:
643 output_data("LINEMODE ");
644 if (length < 2) {
645 output_data(" (empty suboption??\?)");
646 break;
647 }
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;
664 }
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;
676 }
677 break;
678
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;
695 }
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]);
703 }
704 output_data(" %d;", pointer[i+SLC_VALUE]);
705 if ((pointer[i+SLC_VALUE] == IAC) &&
706 (pointer[i+SLC_VALUE+1] == IAC))
707 i++;
708 }
709 for (; i < length; i++)
710 output_data(" ?%d?", pointer[i]);
711 break;
712
713 case LM_MODE:
714 output_data("MODE ");
715 if (length < 3) {
716 output_data("(no mode??\?)");
717 break;
718 }
719 {
720 char tbuf[32];
721
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");
729 }
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]);
739 }
740 break;
741
742 case TELOPT_STATUS: {
743 const char *cp;
744 int j, k;
745
746 output_data("STATUS");
747
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");
759
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]);
772
773 output_data("\r\n");
774 break;
775
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;
788 }
789 pointer[k++] = pointer[j++];
790 }
791 printsub(0, &pointer[i], k - i);
792 if (i < length) {
793 output_data(" SE");
794 i = j;
795 } else
796 i = j - 1;
797
798 output_data("\r\n");
799
800 break;
801
802 default:
803 output_data(" %d", pointer[i]);
804 break;
805 }
806 }
807 break;
808 }
809 break;
810 }
811
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]);
824 }
825 break;
826
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:
843 {
844 static const char NQ[] = "\" ";
845 const char *noquote = NQ;
846 for (i = 2; i < length; i++ ) {
847 switch (pointer[i]) {
848 case NEW_ENV_VAR:
849 output_data("%sVAR ", noquote);
850 noquote = NQ;
851 break;
852
853 case NEW_ENV_VALUE:
854 output_data("%sVALUE ", noquote);
855 noquote = NQ;
856 break;
857
858 case ENV_ESC:
859 output_data("%sESC ", noquote);
860 noquote = NQ;
861 break;
862
863 case ENV_USERVAR:
864 output_data("%sUSERVAR ", noquote);
865 noquote = NQ;
866 break;
867
868 default:
869 if (isprint(pointer[i]) && pointer[i] != '"') {
870 if (*noquote) {
871 output_data("\"");
872 noquote = "";
873 }
874 output_data("%c", pointer[i]);
875 } else {
876 output_data("%s%03o ", noquote, pointer[i]);
877 noquote = NQ;
878 }
879 break;
880 }
881 }
882 if (!noquote)
883 output_data("\"");
884 break;
885 }
886 }
887 break;
888
889 #ifdef AUTHENTICATION
890 case TELOPT_AUTHENTICATION:
891 output_data("AUTHENTICATION");
892
893 if (length < 2) {
894 output_data(" (empty suboption??\?)");
895 break;
896 }
897 switch (pointer[1]) {
898 case TELQUAL_REPLY:
899 case TELQUAL_IS:
900 output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
901 "IS" : "REPLY");
902 if (AUTHTYPE_NAME_OK(pointer[2]))
903 output_data("%s ", AUTHTYPE_NAME(pointer[2]));
904 else
905 output_data("%d ", pointer[2]);
906 if (length < 3) {
907 output_data("(partial suboption??\?)");
908 break;
909 }
910 output_data("%s|%s",
911 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
912 "CLIENT" : "SERVER",
913 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
914 "MUTUAL" : "ONE-WAY");
915
916 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
917 output_data("%s", buf);
918 break;
919
920 case TELQUAL_SEND:
921 i = 2;
922 output_data(" SEND ");
923 while (i < length) {
924 if (AUTHTYPE_NAME_OK(pointer[i]))
925 output_data("%s ", AUTHTYPE_NAME(pointer[i]));
926 else
927 output_data("%d ", pointer[i]);
928 if (++i >= length) {
929 output_data("(partial suboption??\?)");
930 break;
931 }
932 output_data("%s|%s ",
933 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
934 "CLIENT" : "SERVER",
935 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
936 "MUTUAL" : "ONE-WAY");
937 ++i;
938 }
939 break;
940
941 case TELQUAL_NAME:
942 i = 2;
943 output_data(" NAME \"");
944 while (i < length) {
945 if (isprint(pointer[i]))
946 output_data("%c", pointer[i++]);
947 else
948 output_data("\"%03o\"",pointer[i++]);
949 }
950 output_data("\"");
951 break;
952
953 default:
954 for (i = 2; i < length; i++)
955 output_data(" ?%d?", pointer[i]);
956 break;
957 }
958 break;
959 #endif
960
961 #ifdef ENCRYPTION
962 case TELOPT_ENCRYPT:
963 output_data("ENCRYPT");
964 if (length < 2) {
965 output_data(" (empty suboption??\?)");
966 break;
967 }
968 switch (pointer[1]) {
969 case ENCRYPT_START:
970 output_data(" START");
971 break;
972
973 case ENCRYPT_END:
974 output_data(" END");
975 break;
976
977 case ENCRYPT_REQSTART:
978 output_data(" REQUEST-START");
979 break;
980
981 case ENCRYPT_REQEND:
982 output_data(" REQUEST-END");
983 break;
984
985 case ENCRYPT_IS:
986 case ENCRYPT_REPLY:
987 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
988 "IS" : "REPLY");
989 if (length < 3) {
990 output_data(" (partial suboption??\?)");
991 break;
992 }
993 if (ENCTYPE_NAME_OK(pointer[2]))
994 output_data("%s ", ENCTYPE_NAME(pointer[2]));
995 else
996 output_data(" %d (unknown)", pointer[2]);
997
998 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
999 output_data("%s", buf);
1000 break;
1001
1002 case ENCRYPT_SUPPORT:
1003 i = 2;
1004 output_data(" SUPPORT ");
1005 while (i < length) {
1006 if (ENCTYPE_NAME_OK(pointer[i]))
1007 output_data("%s ", ENCTYPE_NAME(pointer[i]));
1008 else
1009 output_data("%d ", pointer[i]);
1010 i++;
1011 }
1012 break;
1013
1014 case ENCRYPT_ENC_KEYID:
1015 output_data(" ENC_KEYID");
1016 goto encommon;
1017
1018 case ENCRYPT_DEC_KEYID:
1019 output_data(" DEC_KEYID");
1020 goto encommon;
1021
1022 default:
1023 output_data(" %d (unknown)", pointer[1]);
1024 encommon:
1025 for (i = 2; i < length; i++)
1026 output_data(" %d", pointer[i]);
1027 break;
1028 }
1029 break;
1030 #endif /* ENCRYPTION */
1031
1032 default:
1033 if (TELOPT_OK(pointer[0]))
1034 output_data("%s (unknown)", TELOPT(pointer[0]));
1035 else
1036 output_data("%d (unknown)", pointer[i]);
1037 for (i = 1; i < length; i++)
1038 output_data(" %d", pointer[i]);
1039 break;
1040 }
1041 output_data("\r\n");
1042 }
1043
1044 /*
1045 * Dump a data buffer in hex and ascii to the output data stream.
1046 */
1047 void
printdata(const char * tag,char * ptr,int cnt)1048 printdata(const char *tag, char *ptr, int cnt)
1049 {
1050 int i;
1051 char xbuf[30];
1052
1053 while (cnt) {
1054 /* flush net output buffer if no room for new data) */
1055 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
1056 netflush();
1057 }
1058
1059 /* add a line of output */
1060 output_data("%s: ", tag);
1061 for (i = 0; i < 20 && cnt; i++) {
1062 output_data("%02x", *ptr);
1063 if (isprint((unsigned char)*ptr)) {
1064 xbuf[i] = *ptr;
1065 } else {
1066 xbuf[i] = '.';
1067 }
1068 if (i % 2)
1069 output_data(" ");
1070 cnt--;
1071 ptr++;
1072 }
1073 xbuf[i] = '\0';
1074 output_data(" %s\r\n", xbuf);
1075 }
1076 }
1077 #endif /* DIAGNOSTICS */
1078