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