2
* Copyright (c) 1989 Regents of the University of California.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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
35
* From: @(#)utility.c 5.8 (Berkeley) 3/22/91
38
"$Id: utility.c,v 1.11 1999/12/12 14:59:45 dholland Exp $";
43
#include <sys/utsname.h>
47
#include <libtelnet/auth.h>
58
static struct buflist head = { next: &head, buf: 0, len: 0 };
59
static struct buflist *tail = &head;
62
static size_t listlen;
64
static struct buflist *urg;
69
* A small subroutine to flush the network output buffer, get some data
70
* from the network, and pass it through the telnet state machine. We
71
* also flush the pty input buffer (by dropping its data) if it becomes
79
DIAG(TD_REPORT, netoprintf("td: ttloop\r\n"););
82
ncc = read(net, netibuf, sizeof(netibuf));
84
syslog(LOG_INFO, "ttloop: read: %m\n");
86
} else if (ncc == 0) {
87
syslog(LOG_INFO, "ttloop: peer died: EOF\n");
90
DIAG(TD_REPORT, netoprintf("td: ttloop read %d chars\r\n", ncc););
92
telrcv(); /* state machine */
94
pfrontp = pbackp = ptyobuf;
100
* Check a descriptor to see if out of band data exists on it.
102
int stilloob(int s) /* socket number */
104
static struct timeval timeout = { 0, 0 };
111
value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
112
} while ((value == -1) && (errno == EINTR));
115
fatalperror(pty, "select");
117
if (FD_ISSET(s, &excepts)) {
128
if ((n = pfrontp - pbackp) > 0) {
129
DIAG((TD_REPORT | TD_PTYDATA),
130
netoprintf("td: ptyflush %d chars\r\n", n););
131
DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
132
n = write(pty, pbackp, n);
135
if (errno == EWOULDBLOCK || errno == EINTR)
140
if (pbackp == pfrontp)
141
pbackp = pfrontp = ptyobuf;
147
* Return the address of the next "item" in the TELNET data
148
* stream. This will be the address of the next character if
149
* the current address is a user data character, or it will
150
* be the address of the character following the TELNET command
151
* if the current address is a TELNET IAC ("I Am a Command")
157
const unsigned char *current, const unsigned char *end,
158
const unsigned char *next, const unsigned char *nextend
160
if (*current++ != IAC) {
161
while (current < end && *current++ != IAC)
166
if (current >= end) {
175
switch (*current++) {
182
case SB: /* loop forever looking for the SE */
186
while (iac = 0, current < end) {
187
if (*current++ == IAC) {
188
if (current >= end) {
193
if (*current++ == SE) {
212
return next ? next + (current - end) : current;
213
} /* end of nextitem */
219
* We are about to do a TELNET SYNCH operation. Clear
220
* the path to the network.
222
* Things are a bit tricky since we may have sent the first
223
* byte or so of a previous TELNET command into the network.
224
* So, we have to scan the network buffer from the beginning
225
* until we are up to where we want to be.
227
* A side effect of what we do, just to keep things
228
* simple, is to clear the urgent data pointer. The principal
229
* caller should be setting the urgent data pointer AFTER calling
237
} /* end of netclear */
242
struct iovec *vector;
247
int ltrailing = trailing;
249
vector = malloc(listlen * sizeof(struct iovec));
254
len = listlen - (doclear & ltrailing);
257
while (lp != &head) {
261
n = send(net, lp->buf, 1, MSG_OOB);
269
v->iov_base = lp->buf;
270
v->iov_len = lp->len;
275
vector->iov_base = (char *)vector->iov_base + skip;
276
vector->iov_len -= skip;
278
n = writev(net, vector, len);
284
if (errno != EWOULDBLOCK && errno != EINTR)
292
while (lp->len <= len) {
293
if (lp == tail && ltrailing) {
299
head.next = lp->next;
316
* Send as much data as possible to the network,
317
* handling requests for urgent data.
322
if (fflush(netfile)) {
333
* miscellaneous functions doing a variety of little jobs follow ...
338
fatal(int f, const char *msg)
342
(void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
344
if (encrypt_output) {
346
* Better turn off encryption first....
353
(void) write(f, buf, (int)strlen(buf));
359
fatalperror(int f, const char *msg)
362
snprintf(buf, sizeof(buf), "%s: %s\r\n", msg, strerror(errno));
367
struct utsname kerninfo;
370
edithost(const char *pat, const char *host)
379
res = realloc(editedhost, strlen(pat) + strlen(host) + 1);
385
fprintf(stderr, "edithost: Out of memory\n");
410
(void) strcpy(res, host);
415
static char *putlocation;
419
putstr(const char *s)
421
while (*s) putchr(*s++);
429
static char fmtstr[] = { "%H:%M on %A, %d %B %Y" };
431
void putf(const char *cp, char *where)
448
slash = strrchr(line, '/');
463
(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
475
if (getdomainname(buff,sizeof(buff)) < 0
477
|| strcmp(buff, "(none)") == 0)
489
if ((fp = fopen(ISSUE_FILE, "r")) == NULL)
492
while ((c = fgetc(fp)) != EOF) {
493
if (p == '\n' && c == '#') {
496
} while (c != EOF && c != '\n');
498
} else if (c == '%') {
506
if (c == '\n') putchr('\r');
513
return; /* ignore remainder of the banner string */
517
putstr(kerninfo.sysname);
521
putstr(kerninfo.machine);
525
putstr(kerninfo.release);
530
putstr(kerninfo.version);
532
puts(kerninfo.version);
542
* Print telnet options and commands in plain text, if possible.
545
printoption(const char *fmt, int option)
547
if (TELOPT_OK(option))
548
netoprintf("%s %s\r\n", fmt, TELOPT(option));
549
else if (TELCMD_OK(option))
550
netoprintf("%s %s\r\n", fmt, TELCMD(option));
552
netoprintf("%s %d\r\n", fmt, option);
555
/* direction: '<' or '>' */
556
/* pointer: where suboption data sits */
557
/* length: length of suboption data */
559
printsub(char direction, unsigned char *pointer, int length)
566
if (!(diagnostic & TD_OPTIONS))
570
netoprintf("td: %s suboption ",
571
direction == '<' ? "recv" : "send");
575
i = pointer[length-2];
576
j = pointer[length-1];
578
if (i != IAC || j != SE) {
579
netoprintf("(terminated by ");
581
netoprintf("%s ", TELOPT(i));
582
else if (TELCMD_OK(i))
583
netoprintf("%s ", TELCMD(i));
585
netoprintf("%d ", i);
587
netoprintf("%s", TELOPT(j));
588
else if (TELCMD_OK(j))
589
netoprintf("%s", TELCMD(j));
592
netoprintf(", not IAC SE!) ");
598
netoprintf("(Empty suboption???)");
601
switch (pointer[0]) {
603
netoprintf("TERMINAL-TYPE ");
604
switch (pointer[1]) {
606
netoprintf("IS \"%.*s\"", length-2, (char *)pointer+2);
612
netoprintf("- unknown qualifier %d (0x%x).",
613
pointer[1], pointer[1]);
617
netoprintf("TERMINAL-SPEED");
619
netoprintf(" (empty suboption???)");
622
switch (pointer[1]) {
624
netoprintf(" IS %.*s", length-2, (char *)pointer+2);
630
netoprintf(" %d (unknown)", pointer[1]);
631
for (i = 2; i < length; i++) {
632
netoprintf(" ?%d?", pointer[i]);
639
netoprintf("TOGGLE-FLOW-CONTROL");
641
netoprintf(" (empty suboption???)");
644
switch (pointer[1]) {
646
netoprintf(" OFF"); break;
648
netoprintf(" ON"); break;
650
netoprintf(" %d (unknown)", pointer[1]);
652
for (i = 2; i < length; i++) {
653
netoprintf(" ?%d?", pointer[i]);
660
netoprintf(" (empty suboption???)");
664
netoprintf(" ?%d?", pointer[1]);
667
netoprintf(" %d %d (%d)",
668
pointer[1], pointer[2],
669
(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
671
netoprintf(" ?%d?", pointer[3]);
674
netoprintf(" %d %d (%d)",
675
pointer[3], pointer[4],
676
(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
677
for (i = 5; i < length; i++) {
678
netoprintf(" ?%d?", pointer[i]);
682
case TELOPT_LINEMODE:
683
netoprintf("LINEMODE ");
685
netoprintf(" (empty suboption???)");
688
switch (pointer[1]) {
702
netoprintf("(no option???)");
705
switch (pointer[2]) {
707
netoprintf("Forward Mask");
708
for (i = 3; i < length; i++) {
709
netoprintf(" %x", pointer[i]);
713
netoprintf("%d (unknown)", pointer[2]);
714
for (i = 3; i < length; i++) {
715
netoprintf(" %d", pointer[i]);
723
for (i = 2; i < length - 2; i += 3) {
724
if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
725
netoprintf(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
727
netoprintf(" %d", pointer[i+SLC_FUNC]);
728
switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
730
netoprintf(" NOSUPPORT"); break;
732
netoprintf(" CANTCHANGE"); break;
734
netoprintf(" VARIABLE"); break;
736
netoprintf(" DEFAULT"); break;
739
pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
740
pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
741
pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
742
if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
743
SLC_FLUSHOUT| SLC_LEVELBITS)) {
744
netoprintf("(0x%x)", pointer[i+SLC_FLAGS]);
746
netoprintf(" %d;", pointer[i+SLC_VALUE]);
747
if ((pointer[i+SLC_VALUE] == IAC) &&
748
(pointer[i+SLC_VALUE+1] == IAC))
751
for (; i < length; i++) {
752
netoprintf(" ?%d?", pointer[i]);
759
netoprintf("(no mode???)");
764
snprintf(tbuf, sizeof(tbuf), "%s%s%s%s%s",
765
pointer[2]&MODE_EDIT ? "|EDIT" : "",
766
pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
767
pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
768
pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
769
pointer[2]&MODE_ACK ? "|ACK" : "");
770
netoprintf("%s", tbuf[1] ? &tbuf[1] : "0");
772
if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
773
netoprintf(" (0x%x)", pointer[2]);
775
for (i = 3; i < length; i++) {
776
netoprintf(" ?0x%x?", pointer[i]);
780
netoprintf("%d (unknown)", pointer[1]);
781
for (i = 2; i < length; i++) {
782
netoprintf(" %d", pointer[i]);
787
case TELOPT_STATUS: {
791
netoprintf("STATUS");
793
switch (pointer[1]) {
795
if (pointer[1] == TELQUAL_SEND)
798
netoprintf(" %d (unknown)", pointer[1]);
799
for (i = 2; i < length; i++) {
800
netoprintf(" ?%d?", pointer[i]);
804
netoprintf(" IS\r\n");
806
for (i = 2; i < length; i++) {
808
case DO: cp = "DO"; goto common2;
809
case DONT: cp = "DONT"; goto common2;
810
case WILL: cp = "WILL"; goto common2;
811
case WONT: cp = "WONT"; goto common2;
814
if (TELOPT_OK((int)pointer[i]))
815
netoprintf(" %s %s", cp, TELOPT(pointer[i]));
817
netoprintf(" %s %d", cp, pointer[i]);
827
if (pointer[j] == SE) {
830
if (pointer[j+1] == SE)
835
pointer[k++] = pointer[j++];
837
printsub(0, &pointer[i], k - i);
849
netoprintf(" %d", pointer[i]);
858
case TELOPT_XDISPLOC:
859
netoprintf("X-DISPLAY-LOCATION ");
860
switch (pointer[1]) {
862
netoprintf("IS \"%.*s\"", length-2, (char *)pointer+2);
868
netoprintf("- unknown qualifier %d (0x%x).",
869
pointer[1], pointer[1]);
874
netoprintf("ENVIRON ");
875
switch (pointer[1]) {
886
register int noquote = 2;
887
for (i = 2; i < length; i++ ) {
888
switch (pointer[i]) {
890
if (pointer[1] == TELQUAL_SEND)
892
netoprintf("\" VAR " + noquote);
897
netoprintf("\" VALUE " + noquote);
902
netoprintf("\" ESC " + noquote);
908
if (isprint(pointer[i]) && pointer[i] != '"') {
913
netoprintf("%c", pointer[i]);
915
netoprintf("\" %03o " + noquote,
929
#if defined(AUTHENTICATE)
930
case TELOPT_AUTHENTICATION:
931
netoprintf("AUTHENTICATION");
934
netoprintf(" (empty suboption???)");
937
switch (pointer[1]) {
940
netoprintf(" %s ", (pointer[1] == TELQUAL_IS) ?
942
if (AUTHTYPE_NAME_OK(pointer[2]))
943
netoprintf("%s ", AUTHTYPE_NAME(pointer[2]));
945
netoprintf("%d ", pointer[2]);
947
netoprintf("(partial suboption???)");
951
((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
953
((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
954
"MUTUAL" : "ONE-WAY");
956
auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
957
netoprintf("%s", buf);
962
netoprintf(" SEND ");
964
if (AUTHTYPE_NAME_OK(pointer[i]))
965
netoprintf("%s ", AUTHTYPE_NAME(pointer[i]));
967
netoprintf("%d ", pointer[i]);
969
netoprintf("(partial suboption???)");
973
((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
975
((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
976
"MUTUAL" : "ONE-WAY");
983
netoprintf(" NAME \"");
987
* *nfrontp += pointer[i++];
990
* but I'm pretty sure that's wrong...
993
netoprintf("%c", pointer[i++]);
998
for (i = 2; i < length; i++) {
999
netoprintf(" ?%d?", pointer[i]);
1006
#if defined(ENCRYPT)
1007
case TELOPT_ENCRYPT:
1008
netoprintf("ENCRYPT");
1010
netoprintf(" (empty suboption???)");
1013
switch (pointer[1]) {
1015
netoprintf(" START");
1022
case ENCRYPT_REQSTART:
1023
netoprintf(" REQUEST-START");
1026
case ENCRYPT_REQEND:
1027
netoprintf(" REQUEST-END");
1032
netoprintf(" %s ", (pointer[1] == ENCRYPT_IS) ?
1035
netoprintf(" (partial suboption???)");
1038
if (ENCTYPE_NAME_OK(pointer[2]))
1039
netoprintf("%s ", ENCTYPE_NAME(pointer[2]));
1041
netoprintf(" %d (unknown)", pointer[2]);
1043
encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1044
netoprintf("%s", buf);
1047
case ENCRYPT_SUPPORT:
1049
netoprintf(" SUPPORT ");
1050
while (i < length) {
1051
if (ENCTYPE_NAME_OK(pointer[i]))
1052
netoprintf("%s ", ENCTYPE_NAME(pointer[i]));
1054
netoprintf("%d ", pointer[i]);
1059
case ENCRYPT_ENC_KEYID:
1060
netoprintf(" ENC_KEYID", pointer[1]);
1063
case ENCRYPT_DEC_KEYID:
1064
netoprintf(" DEC_KEYID", pointer[1]);
1068
netoprintf(" %d (unknown)", pointer[1]);
1070
for (i = 2; i < length; i++) {
1071
netoprintf(" %d", pointer[i]);
1079
if (TELOPT_OK(pointer[0]))
1080
netoprintf("%s (unknown)", TELOPT(pointer[0]));
1082
netoprintf("%d (unknown)", pointer[i]);
1083
for (i = 1; i < length; i++) {
1084
netoprintf(" %d", pointer[i]);
1092
* Dump a data buffer in hex and ascii to the output data stream.
1095
printdata(const char *tag, const char *ptr, int cnt)
1101
/* add a line of output */
1102
netoprintf("%s: ", tag);
1103
for (i = 0; i < 20 && cnt; i++) {
1104
netoprintf("%02x", *ptr);
1105
if (isprint(*ptr)) {
1117
netoprintf(" %s\r\n", xbuf );
1120
#endif /* DIAGNOSTICS */
1122
static struct buflist *
1123
addbuf(const char *buf, size_t len)
1125
struct buflist *bufl;
1127
bufl = malloc(sizeof(struct buflist));
1131
bufl->next = tail->next;
1132
bufl->buf = malloc(len);
1139
tail = tail->next = bufl;
1142
memcpy(bufl->buf, buf, len);
1147
netwrite(void *cookie, const char *buf, size_t len)
1150
const char *const end = buf + len;
1151
int ltrailing = trailing;
1152
int ldoclear = doclear;
1154
#define wewant(p) ((*p&0xff) == IAC) && \
1155
((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)
1162
size_t m = tail->len;
1164
p = nextitem(tail->buf, tail->buf + tail->len, buf, end);
1172
tail->buf = realloc(tail->buf, tail->len);
1177
memcpy(tail->buf + m, buf, l);
1181
trailing = ltrailing;
1185
struct buflist *lpprev;
1199
if (lp == tail && ltrailing) {
1203
if (!wewant(lp->buf)) {
1204
lpprev->next = lp->next;
1218
p = nextitem(buf, end, 0, 0);
1222
} else if (ldoclear) {
1230
if (!addbuf(buf, l)) {
1231
return ret ? ret : -1;
1233
trailing = ltrailing;
1247
static const cookie_io_functions_t funcs = {
1248
read: 0, write: netwrite, seek: 0, close: 0
1251
netfile = fopencookie(0, "w", funcs);
1256
sendurg(const char *buf, size_t len) {
1258
fwrite(buf, 1, len, netfile);
1262
urg = addbuf(buf, len);
1266
netbuflen(int flush) {
1270
return listlen != 1 ? listlen : tail->len - skip;