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