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