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