Fix for Cray UNICOS sessions
[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 *
836fe169 5 * %sccs.include.redist.c%
ea139302
PB
6 */
7
8#ifndef lint
b7c8f459 9static char sccsid[] = "@(#)utility.c 5.8 (Berkeley) %G%";
ea139302
PB
10#endif /* not lint */
11
4a8a7128 12#define PRINTOPTIONS
ea139302
PB
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
1af3d848 28 void
ea139302
PB
29ttloop()
30{
31 void netflush();
32
1af3d848
DB
33 DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
34 nfrontp += strlen(nfrontp);});
ea139302
PB
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 }
1af3d848
DB
46 DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
47 nfrontp += strlen(nfrontp);});
ea139302
PB
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 */
1af3d848 59 int
ea139302 60stilloob(s)
1af3d848 61 int s; /* socket number */
ea139302
PB
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
1af3d848 83 void
ea139302
PB
84ptyflush()
85{
86 int n;
87
4a8a7128 88 if ((n = pfrontp - pbackp) > 0) {
1af3d848
DB
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));
ea139302 93 n = write(pty, pbackp, n);
4a8a7128 94 }
1af3d848
DB
95 if (n < 0) {
96 if (errno == EWOULDBLOCK || errno == EINTR)
97 return;
98 cleanup(0);
99 }
ea139302
PB
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 */
1af3d848 115 char *
ea139302 116nextitem(current)
1af3d848 117 char *current;
ea139302
PB
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 */
1af3d848 162 void
ea139302
PB
163netclear()
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
1af3d848
DB
170#if defined(ENCRYPT)
171 thisitem = nclearto > netobuf ? nclearto : netobuf;
172#else
ea139302 173 thisitem = netobuf;
1af3d848 174#endif
ea139302
PB
175
176 while ((next = nextitem(thisitem)) <= nbackp) {
177 thisitem = next;
178 }
179
180 /* Now, thisitem is first before/at boundary. */
181
1af3d848
DB
182#if defined(ENCRYPT)
183 good = nclearto > netobuf ? nclearto : netobuf;
184#else
ea139302 185 good = netobuf; /* where the good bytes go */
1af3d848 186#endif
ea139302
PB
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 bcopy(thisitem, good, 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 */
1af3d848 215 void
ea139302
PB
216netflush()
217{
218 int n;
219 extern int not42;
220
221 if ((n = nfrontp - nbackp) > 0) {
1af3d848
DB
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#if defined(ENCRYPT)
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 }
4a8a7128 234 }
1af3d848 235#endif
ea139302
PB
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;
1af3d848 263 cleanup(0);
ea139302
PB
264 }
265 nbackp += n;
1af3d848
DB
266#if defined(ENCRYPT)
267 if (nbackp > nclearto)
268 nclearto = 0;
269#endif
ea139302
PB
270 if (nbackp >= neturg) {
271 neturg = 0;
272 }
273 if (nbackp == nfrontp) {
274 nbackp = nfrontp = netobuf;
1af3d848
DB
275#if defined(ENCRYPT)
276 nclearto = 0;
277#endif
ea139302
PB
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 */
1af3d848 293 void
ea139302 294writenet(ptr, len)
1af3d848
DB
295 register unsigned char *ptr;
296 register int len;
ea139302
PB
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 bcopy(ptr, nfrontp, 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
1af3d848 315 void
ea139302
PB
316fatal(f, msg)
317 int f;
318 char *msg;
319{
320 char buf[BUFSIZ];
321
322 (void) sprintf(buf, "telnetd: %s.\r\n", msg);
1af3d848
DB
323#if defined(ENCRYPT)
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
ea139302
PB
333 (void) write(f, buf, (int)strlen(buf));
334 sleep(1); /*XXX*/
335 exit(1);
336}
337
1af3d848 338 void
ea139302
PB
339fatalperror(f, msg)
340 int f;
341 char *msg;
342{
396aa79f 343 char buf[BUFSIZ], *strerror();
ea139302 344
396aa79f 345 (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
ea139302
PB
346 fatal(f, buf);
347}
348
349char editedhost[32];
350
1af3d848 351 void
ea139302
PB
352edithost(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
392static char *putlocation;
393
1af3d848 394 void
ea139302 395putstr(s)
1af3d848 396 register char *s;
ea139302
PB
397{
398
399 while (*s)
400 putchr(*s++);
401}
402
1af3d848 403 void
ea139302 404putchr(cc)
1af3d848 405 int cc;
ea139302
PB
406{
407 *putlocation++ = cc;
408}
409
1af3d848
DB
410/*
411 * This is split on two lines so that SCCS will not see the M
412 * between two % signs and expand it...
413 */
414static char fmtstr[] = { "%l:%M\
415%P on %A, %d %B %Y" };
416
417 void
ea139302 418putf(cp, where)
1af3d848
DB
419 register char *cp;
420 char *where;
ea139302 421{
1af3d848 422 char *slash;
977a0c8c 423 time_t t;
1af3d848 424 char db[100];
ea139302
PB
425 extern char *rindex();
426
427 putlocation = where;
428
429 while (*cp) {
430 if (*cp != '%') {
431 putchr(*cp++);
432 continue;
433 }
434 switch (*++cp) {
435
436 case 't':
437 slash = rindex(line, '/');
438 if (slash == (char *) 0)
439 putstr(line);
440 else
441 putstr(&slash[1]);
442 break;
443
444 case 'h':
445 putstr(editedhost);
446 break;
447
1af3d848 448 case 'd':
977a0c8c 449 (void)time(&t);
1af3d848 450 (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
977a0c8c 451 putstr(db);
ea139302 452 break;
ea139302
PB
453
454 case '%':
455 putchr('%');
456 break;
457 }
458 cp++;
459 }
460}
461
4a8a7128
PB
462#ifdef DIAGNOSTICS
463/*
464 * Print telnet options and commands in plain text, if possible.
465 */
1af3d848 466 void
4a8a7128 467printoption(fmt, option)
1af3d848
DB
468 register char *fmt;
469 register int option;
4a8a7128
PB
470{
471 if (TELOPT_OK(option))
472 sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
473 else if (TELCMD_OK(option))
474 sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
475 else
476 sprintf(nfrontp, "%s %d\r\n", fmt, option);
477 nfrontp += strlen(nfrontp);
478 return;
479}
480
1af3d848
DB
481 void
482printsub(direction, pointer, length)
483 char direction; /* '<' or '>' */
484 unsigned char *pointer; /* where suboption data sits */
485 int length; /* length of suboption data */
4a8a7128
PB
486{
487 register int i;
b7c8f459 488 char buf[512];
4a8a7128 489
1af3d848
DB
490 if (!(diagnostic & TD_OPTIONS))
491 return;
492
493 if (direction) {
494 sprintf(nfrontp, "td: %s suboption ",
495 direction == '<' ? "recv" : "send");
4a8a7128
PB
496 nfrontp += strlen(nfrontp);
497 if (length >= 3) {
498 register int j;
499
500 i = pointer[length-2];
501 j = pointer[length-1];
502
503 if (i != IAC || j != SE) {
504 sprintf(nfrontp, "(terminated by ");
505 nfrontp += strlen(nfrontp);
506 if (TELOPT_OK(i))
507 sprintf(nfrontp, "%s ", TELOPT(i));
508 else if (TELCMD_OK(i))
509 sprintf(nfrontp, "%s ", TELCMD(i));
510 else
511 sprintf(nfrontp, "%d ", i);
512 nfrontp += strlen(nfrontp);
513 if (TELOPT_OK(j))
514 sprintf(nfrontp, "%s", TELOPT(j));
515 else if (TELCMD_OK(j))
516 sprintf(nfrontp, "%s", TELCMD(j));
517 else
518 sprintf(nfrontp, "%d", j);
519 nfrontp += strlen(nfrontp);
520 sprintf(nfrontp, ", not IAC SE!) ");
521 nfrontp += strlen(nfrontp);
522 }
523 }
524 length -= 2;
525 }
526 if (length < 1) {
527 sprintf(nfrontp, "(Empty suboption???)");
528 nfrontp += strlen(nfrontp);
529 return;
530 }
531 switch (pointer[0]) {
532 case TELOPT_TTYPE:
533 sprintf(nfrontp, "TERMINAL-TYPE ");
534 nfrontp += strlen(nfrontp);
535 switch (pointer[1]) {
536 case TELQUAL_IS:
537 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
538 break;
539 case TELQUAL_SEND:
540 sprintf(nfrontp, "SEND");
541 break;
542 default:
543 sprintf(nfrontp,
544 "- unknown qualifier %d (0x%x).",
545 pointer[1], pointer[1]);
546 }
547 nfrontp += strlen(nfrontp);
548 break;
549 case TELOPT_TSPEED:
550 sprintf(nfrontp, "TERMINAL-SPEED");
551 nfrontp += strlen(nfrontp);
552 if (length < 2) {
553 sprintf(nfrontp, " (empty suboption???)");
554 nfrontp += strlen(nfrontp);
555 break;
556 }
557 switch (pointer[1]) {
558 case TELQUAL_IS:
559 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
560 nfrontp += strlen(nfrontp);
561 break;
562 default:
563 if (pointer[1] == 1)
564 sprintf(nfrontp, " SEND");
565 else
566 sprintf(nfrontp, " %d (unknown)", pointer[1]);
567 nfrontp += strlen(nfrontp);
568 for (i = 2; i < length; i++) {
569 sprintf(nfrontp, " ?%d?", pointer[i]);
570 nfrontp += strlen(nfrontp);
571 }
572 break;
573 }
574 break;
575
576 case TELOPT_LFLOW:
577 sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
578 nfrontp += strlen(nfrontp);
579 if (length < 2) {
580 sprintf(nfrontp, " (empty suboption???)");
581 nfrontp += strlen(nfrontp);
582 break;
583 }
584 switch (pointer[1]) {
585 case 0:
586 sprintf(nfrontp, " OFF"); break;
587 case 1:
588 sprintf(nfrontp, " ON"); break;
589 default:
590 sprintf(nfrontp, " %d (unknown)", pointer[1]);
591 }
592 nfrontp += strlen(nfrontp);
593 for (i = 2; i < length; i++) {
594 sprintf(nfrontp, " ?%d?", pointer[i]);
595 nfrontp += strlen(nfrontp);
596 }
597 break;
598
599 case TELOPT_NAWS:
600 sprintf(nfrontp, "NAWS");
601 nfrontp += strlen(nfrontp);
602 if (length < 2) {
603 sprintf(nfrontp, " (empty suboption???)");
604 nfrontp += strlen(nfrontp);
605 break;
606 }
607 if (length == 2) {
608 sprintf(nfrontp, " ?%d?", pointer[1]);
609 nfrontp += strlen(nfrontp);
610 break;
611 }
612 sprintf(nfrontp, " %d %d (%d)",
613 pointer[1], pointer[2],
614 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
615 nfrontp += strlen(nfrontp);
616 if (length == 4) {
617 sprintf(nfrontp, " ?%d?", pointer[3]);
618 nfrontp += strlen(nfrontp);
619 break;
620 }
621 sprintf(nfrontp, " %d %d (%d)",
622 pointer[3], pointer[4],
623 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
624 nfrontp += strlen(nfrontp);
625 for (i = 5; i < length; i++) {
626 sprintf(nfrontp, " ?%d?", pointer[i]);
627 nfrontp += strlen(nfrontp);
628 }
629 break;
630
631 case TELOPT_LINEMODE:
632 sprintf(nfrontp, "LINEMODE ");
633 nfrontp += strlen(nfrontp);
634 if (length < 2) {
635 sprintf(nfrontp, " (empty suboption???)");
636 nfrontp += strlen(nfrontp);
637 break;
638 }
639 switch (pointer[1]) {
640 case WILL:
641 sprintf(nfrontp, "WILL ");
642 goto common;
643 case WONT:
644 sprintf(nfrontp, "WONT ");
645 goto common;
646 case DO:
647 sprintf(nfrontp, "DO ");
648 goto common;
649 case DONT:
650 sprintf(nfrontp, "DONT ");
651 common:
652 nfrontp += strlen(nfrontp);
653 if (length < 3) {
654 sprintf(nfrontp, "(no option???)");
655 nfrontp += strlen(nfrontp);
656 break;
657 }
658 switch (pointer[2]) {
659 case LM_FORWARDMASK:
660 sprintf(nfrontp, "Forward Mask");
661 nfrontp += strlen(nfrontp);
662 for (i = 3; i < length; i++) {
663 sprintf(nfrontp, " %x", pointer[i]);
664 nfrontp += strlen(nfrontp);
665 }
666 break;
667 default:
668 sprintf(nfrontp, "%d (unknown)", pointer[2]);
669 nfrontp += strlen(nfrontp);
670 for (i = 3; i < length; i++) {
671 sprintf(nfrontp, " %d", pointer[i]);
672 nfrontp += strlen(nfrontp);
673 }
674 break;
675 }
676 break;
677
678 case LM_SLC:
679 sprintf(nfrontp, "SLC");
680 nfrontp += strlen(nfrontp);
681 for (i = 2; i < length - 2; i += 3) {
1af3d848
DB
682 if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
683 sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
4a8a7128
PB
684 else
685 sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
686 nfrontp += strlen(nfrontp);
687 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
688 case SLC_NOSUPPORT:
689 sprintf(nfrontp, " NOSUPPORT"); break;
690 case SLC_CANTCHANGE:
691 sprintf(nfrontp, " CANTCHANGE"); break;
692 case SLC_VARIABLE:
693 sprintf(nfrontp, " VARIABLE"); break;
694 case SLC_DEFAULT:
695 sprintf(nfrontp, " DEFAULT"); break;
696 }
697 nfrontp += strlen(nfrontp);
698 sprintf(nfrontp, "%s%s%s",
699 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
700 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
701 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
702 nfrontp += strlen(nfrontp);
703 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
704 SLC_FLUSHOUT| SLC_LEVELBITS)) {
705 sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
706 nfrontp += strlen(nfrontp);
707 }
708 sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
709 nfrontp += strlen(nfrontp);
710 if ((pointer[i+SLC_VALUE] == IAC) &&
711 (pointer[i+SLC_VALUE+1] == IAC))
712 i++;
713 }
714 for (; i < length; i++) {
715 sprintf(nfrontp, " ?%d?", pointer[i]);
716 nfrontp += strlen(nfrontp);
717 }
718 break;
719
720 case LM_MODE:
721 sprintf(nfrontp, "MODE ");
722 nfrontp += strlen(nfrontp);
723 if (length < 3) {
724 sprintf(nfrontp, "(no mode???)");
725 nfrontp += strlen(nfrontp);
726 break;
727 }
728 {
729 char tbuf[32];
730 sprintf(tbuf, "%s%s%s%s%s",
731 pointer[2]&MODE_EDIT ? "|EDIT" : "",
732 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
733 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
734 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
735 pointer[2]&MODE_ACK ? "|ACK" : "");
736 sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
737 nfrontp += strlen(nfrontp);
738 }
739 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
740 sprintf(nfrontp, " (0x%x)", pointer[2]);
741 nfrontp += strlen(nfrontp);
742 }
743 for (i = 3; i < length; i++) {
744 sprintf(nfrontp, " ?0x%x?", pointer[i]);
745 nfrontp += strlen(nfrontp);
746 }
747 break;
748 default:
749 sprintf(nfrontp, "%d (unknown)", pointer[1]);
750 nfrontp += strlen(nfrontp);
751 for (i = 2; i < length; i++) {
752 sprintf(nfrontp, " %d", pointer[i]);
753 nfrontp += strlen(nfrontp);
754 }
755 }
756 break;
757
758 case TELOPT_STATUS: {
759 register char *cp;
760 register int j, k;
761
762 sprintf(nfrontp, "STATUS");
763 nfrontp += strlen(nfrontp);
764
765 switch (pointer[1]) {
766 default:
767 if (pointer[1] == TELQUAL_SEND)
768 sprintf(nfrontp, " SEND");
769 else
770 sprintf(nfrontp, " %d (unknown)", pointer[1]);
771 nfrontp += strlen(nfrontp);
772 for (i = 2; i < length; i++) {
773 sprintf(nfrontp, " ?%d?", pointer[i]);
774 nfrontp += strlen(nfrontp);
775 }
776 break;
777 case TELQUAL_IS:
778 sprintf(nfrontp, " IS\r\n");
779 nfrontp += strlen(nfrontp);
780
781 for (i = 2; i < length; i++) {
782 switch(pointer[i]) {
783 case DO: cp = "DO"; goto common2;
784 case DONT: cp = "DONT"; goto common2;
785 case WILL: cp = "WILL"; goto common2;
786 case WONT: cp = "WONT"; goto common2;
787 common2:
788 i++;
789 if (TELOPT_OK((int)pointer[i]))
790 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
791 else
792 sprintf(nfrontp, " %s %d", cp, pointer[i]);
793 nfrontp += strlen(nfrontp);
794
795 sprintf(nfrontp, "\r\n");
796 nfrontp += strlen(nfrontp);
797 break;
798
799 case SB:
800 sprintf(nfrontp, " SB ");
801 nfrontp += strlen(nfrontp);
802 i++;
803 j = k = i;
804 while (j < length) {
805 if (pointer[j] == SE) {
806 if (j+1 == length)
807 break;
808 if (pointer[j+1] == SE)
809 j++;
810 else
811 break;
812 }
813 pointer[k++] = pointer[j++];
814 }
815 printsub(0, &pointer[i], k - i);
816 if (i < length) {
817 sprintf(nfrontp, " SE");
818 nfrontp += strlen(nfrontp);
819 i = j;
820 } else
821 i = j - 1;
822
823 sprintf(nfrontp, "\r\n");
824 nfrontp += strlen(nfrontp);
825
826 break;
827
828 default:
829 sprintf(nfrontp, " %d", pointer[i]);
830 nfrontp += strlen(nfrontp);
831 break;
832 }
833 }
834 break;
835 }
836 break;
837 }
838
839 case TELOPT_XDISPLOC:
840 sprintf(nfrontp, "X-DISPLAY-LOCATION ");
841 nfrontp += strlen(nfrontp);
842 switch (pointer[1]) {
843 case TELQUAL_IS:
844 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
845 break;
846 case TELQUAL_SEND:
847 sprintf(nfrontp, "SEND");
848 break;
849 default:
850 sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
851 pointer[1], pointer[1]);
852 }
853 nfrontp += strlen(nfrontp);
854 break;
855
856 case TELOPT_ENVIRON:
857 sprintf(nfrontp, "ENVIRON ");
858 nfrontp += strlen(nfrontp);
859 switch (pointer[1]) {
860 case TELQUAL_IS:
861 sprintf(nfrontp, "IS ");
862 goto env_common;
863 case TELQUAL_SEND:
864 sprintf(nfrontp, "SEND ");
865 goto env_common;
866 case TELQUAL_INFO:
867 sprintf(nfrontp, "INFO ");
868 env_common:
869 nfrontp += strlen(nfrontp);
870 {
871 register int noquote = 2;
872 for (i = 2; i < length; i++ ) {
873 switch (pointer[i]) {
874 case ENV_VAR:
875 if (pointer[1] == TELQUAL_SEND)
876 goto def_case;
877 sprintf(nfrontp, "\" VAR " + noquote);
878 nfrontp += strlen(nfrontp);
879 noquote = 2;
880 break;
881
882 case ENV_VALUE:
883 sprintf(nfrontp, "\" VALUE " + noquote);
884 nfrontp += strlen(nfrontp);
885 noquote = 2;
886 break;
887
888 case ENV_ESC:
889 sprintf(nfrontp, "\" ESC " + noquote);
890 nfrontp += strlen(nfrontp);
891 noquote = 2;
892 break;
893
894 default:
895 def_case:
896 if (isprint(pointer[i]) && pointer[i] != '"') {
897 if (noquote) {
898 *nfrontp++ = '"';
899 noquote = 0;
900 }
901 *nfrontp++ = pointer[i];
902 } else {
903 sprintf(nfrontp, "\" %03o " + noquote,
904 pointer[i]);
905 nfrontp += strlen(nfrontp);
906 noquote = 2;
907 }
908 break;
909 }
910 }
911 if (!noquote)
912 *nfrontp++ = '"';
913 break;
914 }
915 }
916 break;
917
1af3d848
DB
918#if defined(AUTHENTICATE)
919 case TELOPT_AUTHENTICATION:
920 sprintf(nfrontp, "AUTHENTICATION");
921 nfrontp += strlen(nfrontp);
922
923 if (length < 2) {
924 sprintf(nfrontp, " (empty suboption???)");
925 nfrontp += strlen(nfrontp);
926 break;
927 }
928 switch (pointer[1]) {
929 case TELQUAL_REPLY:
930 case TELQUAL_IS:
931 sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
932 "IS" : "REPLY");
933 nfrontp += strlen(nfrontp);
934 if (AUTHTYPE_NAME_OK(pointer[2]))
935 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
936 else
937 sprintf(nfrontp, "%d ", pointer[2]);
938 nfrontp += strlen(nfrontp);
939 if (length < 3) {
940 sprintf(nfrontp, "(partial suboption???)");
941 nfrontp += strlen(nfrontp);
942 break;
943 }
944 sprintf(nfrontp, "%s|%s",
b7c8f459 945 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
1af3d848 946 "CLIENT" : "SERVER",
b7c8f459 947 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
1af3d848
DB
948 "MUTUAL" : "ONE-WAY");
949 nfrontp += strlen(nfrontp);
950
951 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
952 sprintf(nfrontp, "%s", buf);
953 nfrontp += strlen(nfrontp);
954 break;
955
956 case TELQUAL_SEND:
957 i = 2;
958 sprintf(nfrontp, " SEND ");
959 nfrontp += strlen(nfrontp);
960 while (i < length) {
961 if (AUTHTYPE_NAME_OK(pointer[i]))
962 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
963 else
964 sprintf(nfrontp, "%d ", pointer[i]);
965 nfrontp += strlen(nfrontp);
966 if (++i >= length) {
967 sprintf(nfrontp, "(partial suboption???)");
968 nfrontp += strlen(nfrontp);
969 break;
970 }
971 sprintf(nfrontp, "%s|%s ",
b7c8f459 972 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
1af3d848 973 "CLIENT" : "SERVER",
b7c8f459 974 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
1af3d848
DB
975 "MUTUAL" : "ONE-WAY");
976 nfrontp += strlen(nfrontp);
977 ++i;
978 }
979 break;
980
b7c8f459
DB
981 case TELQUAL_NAME:
982 i = 2;
983 sprintf(nfrontp, " NAME \"");
984 nfrontp += strlen(nfrontp);
985 while (i < length)
986 *nfrontp += pointer[i++];
987 *nfrontp += '"';
988 break;
989
1af3d848
DB
990 default:
991 for (i = 2; i < length; i++) {
992 sprintf(nfrontp, " ?%d?", pointer[i]);
993 nfrontp += strlen(nfrontp);
994 }
995 break;
996 }
997 break;
998#endif
999
1000#if defined(ENCRYPT)
1001 case TELOPT_ENCRYPT:
1002 sprintf(nfrontp, "ENCRYPT");
1003 nfrontp += strlen(nfrontp);
1004 if (length < 2) {
1005 sprintf(nfrontp, " (empty suboption???)");
1006 nfrontp += strlen(nfrontp);
1007 break;
1008 }
1009 switch (pointer[1]) {
1010 case ENCRYPT_START:
1011 sprintf(nfrontp, " START");
1012 nfrontp += strlen(nfrontp);
1013 break;
1014
1015 case ENCRYPT_END:
1016 sprintf(nfrontp, " END");
1017 nfrontp += strlen(nfrontp);
1018 break;
1019
1020 case ENCRYPT_REQSTART:
1021 sprintf(nfrontp, " REQUEST-START");
1022 nfrontp += strlen(nfrontp);
1023 break;
1024
1025 case ENCRYPT_REQEND:
1026 sprintf(nfrontp, " REQUEST-END");
1027 nfrontp += strlen(nfrontp);
1028 break;
1029
1030 case ENCRYPT_IS:
1031 case ENCRYPT_REPLY:
1032 sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
1033 "IS" : "REPLY");
1034 nfrontp += strlen(nfrontp);
1035 if (length < 3) {
1036 sprintf(nfrontp, " (partial suboption???)");
1037 nfrontp += strlen(nfrontp);
1038 break;
1039 }
1040 if (ENCTYPE_NAME_OK(pointer[2]))
1041 sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
1042 else
1043 sprintf(nfrontp, " %d (unknown)", pointer[2]);
1044 nfrontp += strlen(nfrontp);
1045
1046 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1047 sprintf(nfrontp, "%s", buf);
1048 nfrontp += strlen(nfrontp);
1049 break;
1050
1051 case ENCRYPT_SUPPORT:
1052 i = 2;
1053 sprintf(nfrontp, " SUPPORT ");
1054 nfrontp += strlen(nfrontp);
1055 while (i < length) {
1056 if (ENCTYPE_NAME_OK(pointer[i]))
1057 sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
1058 else
1059 sprintf(nfrontp, "%d ", pointer[i]);
1060 nfrontp += strlen(nfrontp);
1061 i++;
1062 }
1063 break;
1064
b7c8f459
DB
1065 case ENCRYPT_ENC_KEYID:
1066 sprintf(nfrontp, " ENC_KEYID", pointer[1]);
1067 nfrontp += strlen(nfrontp);
1068 goto encommon;
1069
1070 case ENCRYPT_DEC_KEYID:
1071 sprintf(nfrontp, " DEC_KEYID", pointer[1]);
1072 nfrontp += strlen(nfrontp);
1073 goto encommon;
1074
1af3d848 1075 default:
b7c8f459 1076 sprintf(nfrontp, " %d (unknown)", pointer[1]);
1af3d848 1077 nfrontp += strlen(nfrontp);
b7c8f459 1078 encommon:
1af3d848
DB
1079 for (i = 2; i < length; i++) {
1080 sprintf(nfrontp, " %d", pointer[i]);
1081 nfrontp += strlen(nfrontp);
1082 }
1083 break;
1084 }
1085 break;
1086#endif
1087
4a8a7128 1088 default:
1af3d848
DB
1089 if (TELOPT_OK(pointer[0]))
1090 sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
1091 else
1092 sprintf(nfrontp, "%d (unknown)", pointer[i]);
4a8a7128 1093 nfrontp += strlen(nfrontp);
1af3d848 1094 for (i = 1; i < length; i++) {
4a8a7128
PB
1095 sprintf(nfrontp, " %d", pointer[i]);
1096 nfrontp += strlen(nfrontp);
1097 }
1098 break;
1099 }
1100 sprintf(nfrontp, "\r\n");
1101 nfrontp += strlen(nfrontp);
1102}
1103
1104/*
1105 * Dump a data buffer in hex and ascii to the output data stream.
1106 */
1af3d848 1107 void
4a8a7128 1108printdata(tag, ptr, cnt)
1af3d848
DB
1109 register char *tag;
1110 register char *ptr;
1111 register int cnt;
4a8a7128 1112{
1af3d848
DB
1113 register int i;
1114 char xbuf[30];
4a8a7128
PB
1115
1116 while (cnt) {
1117 /* flush net output buffer if no room for new data) */
1118 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
1119 netflush();
1120 }
1121
1122 /* add a line of output */
1123 sprintf(nfrontp, "%s: ", tag);
1124 nfrontp += strlen(nfrontp);
1125 for (i = 0; i < 20 && cnt; i++) {
1126 sprintf(nfrontp, "%02x", *ptr);
1127 nfrontp += strlen(nfrontp);
1128 if (isprint(*ptr)) {
1129 xbuf[i] = *ptr;
1130 } else {
1131 xbuf[i] = '.';
1132 }
1133 if (i % 2) {
1134 *nfrontp = ' ';
1135 nfrontp++;
1136 }
1137 cnt--;
1138 ptr++;
1139 }
1140 xbuf[i] = '\0';
1141 sprintf(nfrontp, " %s\r\n", xbuf );
1142 nfrontp += strlen(nfrontp);
1143 }
1144}
4a8a7128 1145#endif /* DIAGNOSTICS */