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