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