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