diff --git a/ChangeLog b/ChangeLog index a96f3d10..170b5fe6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ $Id$ v0.39.2 21-Nov-2003 + NOTE: Don't use this version yet, mbtelnetd might be removed again! + general: With the use of a proxy based on the iftelnetd from the ifmail package incoming telnet sessions are now supported. Outgoing @@ -11,9 +13,13 @@ v0.39.2 21-Nov-2003 upgrade: See mbtelnetd.html how to install mbtelnetd. + common.a: + A small fix in printable function. + mbcico: If called by inetd with the -t itn parameters, mbcico aborts and writes a short instruction in the log to install mbtelnetd. + Outgoing telnet works almost. mbtelnetd: New program, a proxy to handle incoming telnet/vmodem sessions. diff --git a/lib/clcomm.c b/lib/clcomm.c index 31d99db4..26de8cd8 100644 --- a/lib/clcomm.c +++ b/lib/clcomm.c @@ -497,7 +497,7 @@ char *printable(char *s, int l) case '\n': *p++='\\'; *p++='n'; break; case '\t': *p++='\\'; *p++='t'; break; case '\b': *p++='\\'; *p++='b'; break; - default: sprintf(p,"\\%02x",*s); p+=3; break; + default: sprintf(p,"\\%02x", (*s & 0xff)); p+=3; break; } s++; } diff --git a/mbcico/Makefile b/mbcico/Makefile index b6cddf6b..6d62bef8 100644 --- a/mbcico/Makefile +++ b/mbcico/Makefile @@ -138,6 +138,6 @@ mbcico.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/recor outstat.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbftn.h ../lib/mberrors.h scanout.h callstat.h outstat.h nlinfo.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h nlinfo.h mbout.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbftn.h ../lib/mberrors.h outstat.h nlinfo.h -mbtelnetd.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/mberrors.h telnio.h mbtelnetd.h -telnio.o: ../config.h ../lib/libs.h ../lib/clcomm.h telnio.h +mbtelnetd.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/mberrors.h hydra.h telnio.h mbtelnetd.h +telnio.o: ../config.h ../lib/libs.h ../lib/clcomm.h hydra.h telnio.h # End of generated dependencies diff --git a/mbcico/mbtelnetd.c b/mbcico/mbtelnetd.c index 7f0b536f..6aa4ef5a 100644 --- a/mbcico/mbtelnetd.c +++ b/mbcico/mbtelnetd.c @@ -55,34 +55,18 @@ #include "../lib/clcomm.h" #include "../lib/dbcfg.h" #include "../lib/mberrors.h" +#include "hydra.h" +#include "telnio.h" #include "mbtelnetd.h" -#define MBT_BUFSIZ 8192 #define MBT_TIMEOUT 3600 void die(int); -int init_telnet(void); -void answer(int, int); -int read0(char *, int); -int write1(char *, int); void com_gw(int); -#define WILL 251 -#define WONT 252 -#define DO 253 -#define DONT 254 -#define IAC 255 - -#define TN_TRANSMIT_BINARY 0 -#define TN_ECHO 1 -#define TN_SUPPRESS_GA 3 - - - -static int tellen; char *envptr = NULL; time_t t_start, t_end; @@ -200,11 +184,11 @@ int main(int ac, char **av) die(MBERR_INIT_ERROR); } - init_telnet(); + telnet_init(); tmp = calloc(81, sizeof(char )); sprintf(tmp, "mbtelnetd v%s\r\n", VERSION); - write1(tmp, strlen(tmp)); + telnet_write(tmp, strlen(tmp)); free(tmp); com_gw(s); @@ -218,139 +202,12 @@ int main(int ac, char **av) -/* --- This is an artwork of serge terekhov, 2:5000/13@fidonet :) --- */ - -void answer (int tag, int opt) -{ - char buf[3]; - char *r = (char *)"???"; - - switch (tag) { - case WILL: - r = (char *)"WILL"; - break; - case WONT: - r = (char *)"WONT"; - break; - case DO: - r = (char *)"DO"; - break; - case DONT: - r = (char *)"DONT"; - break; - } - Syslog('s', "TELNET send %s %d", r, opt); - - buf[0] = IAC; - buf[1] = tag; - buf[2] = opt; - if (write (1, buf, 3) != 3) - WriteError("$answer cant send"); -} - - - -int init_telnet(void) -{ - tellen = 0; - answer (DO, TN_SUPPRESS_GA); - answer (WILL, TN_SUPPRESS_GA); - answer (DO, TN_TRANSMIT_BINARY); - answer (WILL, TN_TRANSMIT_BINARY); - answer (DO, TN_ECHO); - answer (WILL, TN_ECHO); - return 1; -} - - - -int read0 (char *buf, int len) -{ - int n = 0, m; - char *q, *p; - static char telbuf[4]; - - while ((n == 0) && (n = read (0, buf + tellen, MBT_BUFSIZ - tellen)) > 0) { - if (tellen) { - memcpy(buf, telbuf, tellen); - n += tellen; - tellen = 0; - } - - if (memchr (buf, IAC, n)) { - for (p = q = buf; n--; ) - if ((m = (unsigned char)*q++) != IAC) - *p++ = m; - else { - if (n < 2) { - memcpy (telbuf, q - 1, tellen = n + 1); - break; - } - --n; - switch (m = (unsigned char)*q++) { - case WILL: m = (unsigned char)*q++; --n; - Syslog('s', "TELNET: recv WILL %d", m); - if (m != TN_TRANSMIT_BINARY && m != TN_SUPPRESS_GA && m != TN_ECHO) - answer (DONT, m); - break; - case WONT: m = *q++; - --n; - Syslog('s', "TELNET: recv WONT %d", m); - break; - case DO: m = (unsigned char)*q++; - --n; - Syslog('s', "TELNET: recv DO %d", m); - if (m != TN_TRANSMIT_BINARY && m != TN_SUPPRESS_GA && m != TN_ECHO) - answer (WONT, m); - break; - case DONT: m = (unsigned char)*q++; - --n; - Syslog('s', "TELNET: recv DONT %d", m); - break; - case IAC: *p++ = IAC; - break; - default: Syslog('s', "TELNET: recv IAC %d", m); - break; - } - } - n = p - buf; - } - } - - return n; -} - - - -int write1 (char *buf, int len) -{ - char *q; - int k, l; - - l = len; - while ((len > 0) && (q = memchr(buf, IAC, len))) { - k = (q - buf) + 1; - if ((write (1, buf, k) != k) || (write (1, q, 1) != 1)) { - return -1; - } - buf += k; - len -= k; - } - - if ((len > 0) && write (1, buf, len) != len) { - return -1; - } - return l; -} - - - void com_gw(int in) { fd_set fds; int n, fdsbits; static struct timeval tout = { MBT_TIMEOUT, 0 }; - unsigned char buf[MBT_BUFSIZ]; + unsigned char buf[H_ZIPBUFLEN]; alarm(0); fdsbits = in + 1; @@ -366,7 +223,7 @@ void com_gw(int in) if ((n = select(fdsbits, &fds, NULL, NULL, &tout)) > 0) { if (FD_ISSET(in, &fds)) { if ((n = read(in, buf, sizeof buf)) > 0) { - if (write1(buf, n) < 0) { + if (telnet_write(buf, n) < 0) { goto bad; } } else { @@ -374,7 +231,7 @@ void com_gw(int in) } } if (FD_ISSET(0, &fds)) { - if ((n = read0(buf, sizeof buf)) > 0) { + if ((n = telnet_read(buf, sizeof buf)) > 0) { if (write(in, buf, n) < 0) goto bad; } else { goto bad; diff --git a/mbcico/opentcp.c b/mbcico/opentcp.c index 9e5710d8..28f2f259 100644 --- a/mbcico/opentcp.c +++ b/mbcico/opentcp.c @@ -221,42 +221,3 @@ void closetcp(void) } -#ifdef USE_TELNET - -#define WILL 251 -#define WONT 252 -#define DO 253 -#define DONT 254 -#define IAC 255 - -#define TOPT_BIN 0 -#define TOPT_ECHO 1 -#define TOPT_SUPP 3 - - -static void telnet_answer(int tag, int opt) -{ - char buf[3]; - - Syslog('s', "telnet_answer(%d, %d)", tag, opt); - buf[0]=IAC; - buf[1]=tag; - buf[2]=opt; - tty_put(buf, 3); -} - - -void telnet_init(void) -{ - Syslog('s', "telnet_init()"); - telnet_answer(DO,TOPT_SUPP); - telnet_answer(WILL,TOPT_SUPP); - telnet_answer(DO,TOPT_BIN); - telnet_answer(WILL,TOPT_BIN); - telnet_answer(DO,TOPT_ECHO); - telnet_answer(WILL,TOPT_ECHO); -} - - -#endif - diff --git a/mbcico/opentcp.h b/mbcico/opentcp.h index ee4821c4..9e8d9e94 100644 --- a/mbcico/opentcp.h +++ b/mbcico/opentcp.h @@ -6,8 +6,4 @@ int opentcp(char *); void closetcp(void); -#ifdef USE_TELNET -void telnet_init(void); -#endif - #endif diff --git a/mbcico/telnio.c b/mbcico/telnio.c new file mode 100644 index 00000000..1a5f93a1 --- /dev/null +++ b/mbcico/telnio.c @@ -0,0 +1,249 @@ +/***************************************************************************** + * + * $id$ + * Purpose ...............: Telnet IO filter + * + ***************************************************************************** + * Copyright (C) 1997-2003 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + +#include "../config.h" +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "hydra.h" +#include "telnio.h" + + +static int tellen; + + + +/* --- This is an artwork of serge terekhov, 2:5000/13@fidonet :) --- */ + +void telnet_answer(int tag, int opt) +{ + char buf[3]; + char *r = (char *)"???"; + + switch (tag) { + case WILL: + r = (char *)"WILL"; + break; + case WONT: + r = (char *)"WONT"; + break; + case DO: + r = (char *)"DO"; + break; + case DONT: + r = (char *)"DONT"; + break; + } + Syslog('s', "TELNET send %s %d", r, opt); + + buf[0] = IAC; + buf[1] = tag; + buf[2] = opt; + if (write (1, buf, 3) != 3) + WriteError("$answer cant send"); +} + + + +int telnet_init(void) +{ + Syslog('s', "telnet_init()"); + tellen = 0; + telnet_answer(DO, TOPT_SUPP); + telnet_answer(WILL, TOPT_SUPP); + telnet_answer(DO, TOPT_BIN); + telnet_answer(WILL, TOPT_BIN); + telnet_answer(DO, TOPT_ECHO); + telnet_answer(WILL, TOPT_ECHO); + return 1; +} + + + +/* + * Read function for mbtelnetd + */ +int telnet_read(char *buf, int len) +{ + int n = 0, m; + char *q, *p; + static char telbuf[4]; + + Syslog('s', "telnet_read(buf, %d tellen=%d)", len, tellen); + while ((n == 0) && (n = read (0, buf + tellen, H_ZIPBUFLEN - tellen)) > 0) { + + Syslog('s', " n=%d tellen=%d", n, tellen); + if (n < 0) { + Syslog('s', "telnet_read n=%d", n); + return n; + } + + if (tellen) { + Syslog('s', " memcpy"); + memcpy(buf, telbuf, tellen); + n += tellen; + tellen = 0; + } + + if (memchr (buf, IAC, n)) { + Syslog('s', " IAC detected"); + for (p = q = buf; n--; ) + if ((m = (unsigned char)*q++) != IAC) + *p++ = m; + else { + if (n < 2) { + memcpy (telbuf, q - 1, tellen = n + 1); + break; + } + --n; + switch (m = (unsigned char)*q++) { + case WILL: m = (unsigned char)*q++; --n; + Syslog('s', "TELNET: recv WILL %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(DONT, m); + break; + case WONT: m = *q++; + --n; + Syslog('s', "TELNET: recv WONT %d", m); + break; + case DO: m = (unsigned char)*q++; + --n; + Syslog('s', "TELNET: recv DO %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(WONT, m); + break; + case DONT: m = (unsigned char)*q++; + --n; + Syslog('s', "TELNET: recv DONT %d", m); + break; + case IAC: Syslog('s', "TELNET: recv 2nd IAC %d", m); + *p++ = IAC; + break; + default: Syslog('s', "TELNET: recv IAC %d", m); + break; + } + } + n = p - buf; + } + } + + Syslog('s', " return n=%d", n); + return n; +} + + + +/* + * Telnet output filter, IAC characters are escaped. + */ +int telnet_write(char *buf, int len) +{ + char *q; + int k, l; + + Syslog('s', "telnet_write(buf, %d)", len); + l = len; + while ((len > 0) && (q = memchr(buf, IAC, len))) { + k = (q - buf) + 1; + if ((write(1, buf, k) != k) || (write(1, q, 1) != 1)) { + return -1; + } + buf += k; + len -= k; + } + + if ((len > 0) && write(1, buf, len) != len) { + return -1; + } + return l; +} + + + +int telnet_buffer(char *buf, int len) +{ + int i, j, m = 0, rc; + + rc = len; + + if (memchr (buf, IAC, rc)) { + Syslog('s', "telnet_buffer: IAC in input stream rc=%d", rc); +// Syslogp('s', printable(buf, rc)); + j = 0; + for (i = 0; i < rc; i++) { + if ((buf[i] & 0xff) == IAC) { + i++; + switch (buf[i] & 0xff) { + case WILL: i++; + m = buf[i] & 0xff; + Syslog('s', "Telnet recv WILL %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(DONT, m); + break; + case WONT: i++; + m = buf[i] & 0xff; + Syslog('s', "Telnet recv WONT %d", m); + break; + case DO: i++; + m = buf[i] & 0xff; + Syslog('s', "Telnet recv DO %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(WONT, m); + break; + case DONT: i++; + m = buf[i] & 0xff; + Syslog('s', "Telnet recv DONT %d", m); + break; + case IAC: buf[j] = buf[i]; + j++; + Syslog('s', "Telnet recv escaped IAC"); + break; + default: m = buf[i] & 0xff; + Syslog('s', "TELNET: recv IAC %d, this is not good", m); + buf[j] = IAC; + j++; + buf[j] = m; + j++; + break; + } + } else { + buf[j] = buf[i]; + j++; + } + } + rc = j; +// Syslog('s', "new rc=%d", rc); +// Syslogp('s', printable(buf, rc)); + } + + return rc; +} + + diff --git a/mbcico/telnio.h b/mbcico/telnio.h new file mode 100644 index 00000000..4c9bfc4c --- /dev/null +++ b/mbcico/telnio.h @@ -0,0 +1,23 @@ +#ifndef _TELNIO_H +#define _TELNIO_H + +/* $Id$ */ + + +#define MBT_WILL 251 +#define MBT_WONT 252 +#define MBT_DO 253 +#define MBT_DONT 254 +#define MBT_IAC 255 + +#define TOPT_BIN 0 +#define TOPT_ECHO 1 +#define TOPT_SUPP 3 + +void telnet_answer(int, int); +int telnet_init(void); +int telnet_read(char *, int); +int telnet_write(char *, int); +int telnet_buffer(char *, int); + +#endif diff --git a/mbcico/ttyio.c b/mbcico/ttyio.c index e31c7a57..a1c3c7dc 100644 --- a/mbcico/ttyio.c +++ b/mbcico/ttyio.c @@ -38,14 +38,17 @@ #include "../lib/records.h" #include "../lib/common.h" #include "../lib/clcomm.h" +#include "telnio.h" #include "ttyio.h" #include "lutil.h" extern int hanged_up; +extern int telnet; +extern int master; extern char *inetaddr; -#define TT_BUFSIZ 1024 -#define NUMTIMERS 3 +#define TT_BUFSIZ 1024 +#define NUMTIMERS 3 int tty_status = 0; @@ -241,6 +244,10 @@ static int tty_read(char *buf, int size, int tot) Syslog('!', "tty_read: error flag"); } rc=-tty_status; + } else { + if (master && telnet) { + rc = telnet_buffer(buf, rc); + } } return rc; @@ -253,7 +260,10 @@ int tty_write(char *buf, int size) int result; tty_status=0; - result = write(1,buf,size); + if (telnet && master) + result = telnet_write(buf, size); + else + result = write(1, buf, size); if (result != size) { if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { @@ -461,135 +471,141 @@ int tty_getc(int tot) int tty_get(char *buf, int size, int tot) { - int result=0; + int result=0; - if (left >= size) { - memcpy(buf,next,size); - next += size; - left -= size; - return 0; - } + if (left >= size) { + memcpy(buf,next,size); + next += size; + left -= size; + return 0; + } - if (left > 0) { - memcpy(buf,next,left); - buf += left; - next += left; - size -= left; - left=0; - } + if (left > 0) { + memcpy(buf,next,left); + buf += left; + next += left; + size -= left; + left=0; + } - while ((result=tty_read(buf,size,tot)) > 0) { - buf += result; - size -= result; - } + while ((result=tty_read(buf,size,tot)) > 0) { + buf += result; + size -= result; + } - return result; + return result; } int tty_putc(int c) { - char buf = c; + char buf = c; - return tty_write(&buf,1); + return tty_write(&buf,1); } int tty_put(char *buf, int size) { - return tty_write(buf,size); + return tty_write(buf,size); } int tty_putget(char **obuf, int *osize, char **ibuf, int *isize) { - time_t timeout, now; - int i, rc; - fd_set readfds, writefds, exceptfds; - struct timeval seltimer; + time_t timeout, now; + int i, rc; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; - tty_status = 0; - now = time(NULL); - timeout = (time_t)300; /* maximum of 5 minutes */ + tty_status = 0; + now = time(NULL); + timeout = (time_t)300; /* maximum of 5 minutes */ - for (i = 0; i < NUMTIMERS; i++) { - if (timer[i]) { - if (now >= timer[i]) { - tty_status = STAT_TIMEOUT; - WriteError("tty_putget: timer %d already expired, return",i); - return -tty_status; - } else { - if (timeout > (timer[i]-now)) - timeout=timer[i]-now; - } - } + for (i = 0; i < NUMTIMERS; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status = STAT_TIMEOUT; + WriteError("tty_putget: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout=timer[i]-now; + } } + } - Syslog('t', "tty_putget: timeout=%d",timeout); + Syslog('t', "tty_putget: timeout=%d",timeout); - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - FD_SET(0,&readfds); - FD_SET(1,&writefds); - FD_SET(0,&exceptfds); - FD_SET(1,&exceptfds); - seltimer.tv_sec=timeout; - seltimer.tv_usec=0; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(0,&readfds); + FD_SET(1,&writefds); + FD_SET(0,&exceptfds); + FD_SET(1,&exceptfds); + seltimer.tv_sec=timeout; + seltimer.tv_usec=0; - rc=select(2,&readfds,&writefds,&exceptfds,&seltimer); - if (rc < 0) { - if (hanged_up) { - tty_status=STAT_HANGUP; - WriteError("tty_putget: hanged_up flag"); - } else { - WriteError("$tty_putget: select failed"); - tty_status=STAT_ERROR; - } - } else if (rc == 0) { - tty_status=STAT_TIMEOUT; + rc=select(2,&readfds,&writefds,&exceptfds,&seltimer); + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("tty_putget: hanged_up flag"); } else { - /* rc > 0 */ - if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { - WriteError("$tty_putget: exeption error"); - tty_status=STAT_ERROR; - } + WriteError("$tty_putget: select failed"); + tty_status=STAT_ERROR; } - - if (tty_status) { - Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]); - return -tty_status; + } else if (rc == 0) { + tty_status=STAT_TIMEOUT; + } else { + /* rc > 0 */ + if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { + WriteError("$tty_putget: exeption error"); + tty_status=STAT_ERROR; } + } - if (FD_ISSET(0,&readfds) && *isize) { - rc=read(0,*ibuf,*isize); - if (rc < 0) { - WriteError("$tty_putget: read failed"); - tty_status=STAT_ERROR; - } else { - (*ibuf)+=rc; - (*isize)-=rc; - } + if (tty_status) { + Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]); + return -tty_status; + } + + if (FD_ISSET(0,&readfds) && *isize) { + rc = read(0, *ibuf, *isize); + if (rc < 0) { + WriteError("$tty_putget: read failed"); + tty_status=STAT_ERROR; + } else { + if (master && telnet) { + rc = telnet_buffer(*ibuf, rc); + } + (*ibuf)+=rc; + (*isize)-=rc; } + } - if (FD_ISSET(1,&writefds) && *osize) { - rc=write(1,*obuf,*osize); - if (rc < 0) { - WriteError("$tty_putget: write failed"); - tty_status=STAT_ERROR; - } else { - (*obuf)+=rc; - (*osize)-=rc; - } + if (FD_ISSET(1,&writefds) && *osize) { + if (telnet && master) + rc = telnet_write(*obuf,*osize); + else + rc=write(1,*obuf,*osize); + if (rc < 0) { + WriteError("$tty_putget: write failed"); + tty_status=STAT_ERROR; + } else { + (*obuf)+=rc; + (*osize)-=rc; } + } - if (tty_status) - return -tty_status; - else - return ((*isize == 0) | ((*osize == 0) << 1)); + if (tty_status) + return -tty_status; + else + return ((*isize == 0) | ((*osize == 0) << 1)); }